diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index a9c19c7cb77d9..7705970999174 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -198,10 +198,13 @@ BridgedDeclNameRef_createParsed(BridgedDeclBaseName cBaseName); class BridgedDeclNameLoc { const void *_Nullable LocationInfo; - size_t NumArgumentLabels; + uint32_t NumArgumentLabels; + bool HasModuleSelectorLoc; public: - BridgedDeclNameLoc() : LocationInfo(nullptr), NumArgumentLabels(0) {} + BridgedDeclNameLoc() + : LocationInfo(nullptr), NumArgumentLabels(0), HasModuleSelectorLoc(false) + {} BRIDGED_INLINE BridgedDeclNameLoc(swift::DeclNameLoc loc); @@ -1015,11 +1018,12 @@ BridgedDocumentationAttr BridgedDocumentationAttr_createParsed( SWIFT_NAME( "BridgedDynamicReplacementAttr.createParsed(_:atLoc:attrNameLoc:lParenLoc:" - "replacedFunction:rParenLoc:)") + "replacedFunction:replacedFunctionLoc:rParenLoc:)") BridgedDynamicReplacementAttr BridgedDynamicReplacementAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedSourceLoc cAttrNameLoc, BridgedSourceLoc cLParenLoc, - BridgedDeclNameRef cReplacedFunction, BridgedSourceLoc cRParenLoc); + BridgedDeclNameRef cReplacedFunction, + BridgedDeclNameLoc cReplacedFunctionLoc, BridgedSourceLoc cRParenLoc); enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedEffectsKind { BridgedEffectsKindReadNone, @@ -1388,13 +1392,14 @@ enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedSpecializationKind : uint8_t { }; SWIFT_NAME("BridgedSpecializeAttr.createParsed(_:atLoc:range:whereClause:" - "exported:kind:taretFunction:spiGroups:availableAttrs:)") + "exported:kind:targetFunction:targetFunctionLoc:spiGroups:" + "availableAttrs:)") BridgedSpecializeAttr BridgedSpecializeAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedSourceRange cRange, BridgedNullableTrailingWhereClause cWhereClause, bool exported, BridgedSpecializationKind cKind, - BridgedDeclNameRef cTargetFunction, BridgedArrayRef cSPIGroups, - BridgedArrayRef cAvailableAttrs); + BridgedDeclNameRef cTargetFunction, BridgedDeclNameLoc cTargetFunctionLoc, + BridgedArrayRef cSPIGroups, BridgedArrayRef cAvailableAttrs); SWIFT_NAME( "BridgedSPIAccessControlAttr.createParsed(_:atLoc:range:spiGroupName:)") diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index 75228fe0f4cb6..edc95828d9d9a 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -87,10 +87,12 @@ swift::DeclNameRef BridgedDeclNameRef::unbridged() const { BridgedDeclNameLoc::BridgedDeclNameLoc(swift::DeclNameLoc loc) : LocationInfo(loc.LocationInfo), - NumArgumentLabels(loc.NumArgumentLabels) {} + NumArgumentLabels(loc.NumArgumentLabels), + HasModuleSelectorLoc(loc.HasModuleSelectorLoc) {} swift::DeclNameLoc BridgedDeclNameLoc::unbridged() const { - return swift::DeclNameLoc(LocationInfo, NumArgumentLabels); + return swift::DeclNameLoc(LocationInfo, NumArgumentLabels, + HasModuleSelectorLoc); } //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 9cf98597514c6..66b1983d556f2 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -1207,19 +1207,22 @@ class DynamicReplacementAttr final friend class DynamicallyReplacedDeclRequest; DeclNameRef ReplacedFunctionName; + DeclNameLoc ReplacedFunctionNameLoc; LazyMemberLoader *Resolver = nullptr; uint64_t ResolverContextData; /// Create an @_dynamicReplacement(for:) attribute written in the source. DynamicReplacementAttr(SourceLoc atLoc, SourceRange baseRange, DeclNameRef replacedFunctionName, + DeclNameLoc replacedFunctionNameLoc, SourceRange parenRange); DynamicReplacementAttr(DeclNameRef name, AbstractFunctionDecl *f) : DeclAttribute(DeclAttrKind::DynamicReplacement, SourceLoc(), SourceRange(), /*Implicit=*/false), - ReplacedFunctionName(name), Resolver(nullptr), ResolverContextData(0) { + ReplacedFunctionName(name), ReplacedFunctionNameLoc(), + Resolver(nullptr), ResolverContextData(0) { Bits.DynamicReplacementAttr.HasTrailingLocationInfo = false; } @@ -1228,8 +1231,8 @@ class DynamicReplacementAttr final : DeclAttribute(DeclAttrKind::DynamicReplacement, SourceLoc(), SourceRange(), /*Implicit=*/false), - ReplacedFunctionName(name), Resolver(Resolver), - ResolverContextData(Data) { + ReplacedFunctionName(name), ReplacedFunctionNameLoc(), + Resolver(Resolver), ResolverContextData(Data) { Bits.DynamicReplacementAttr.HasTrailingLocationInfo = false; } @@ -1250,7 +1253,8 @@ class DynamicReplacementAttr final public: static DynamicReplacementAttr * create(ASTContext &Context, SourceLoc AtLoc, SourceLoc DynReplLoc, - SourceLoc LParenLoc, DeclNameRef replacedFunction, SourceLoc RParenLoc); + SourceLoc LParenLoc, DeclNameRef replacedFunction, + DeclNameLoc replacedFunctionNameLoc, SourceLoc RParenLoc); static DynamicReplacementAttr *create(ASTContext &ctx, DeclNameRef replacedFunction, @@ -1265,6 +1269,10 @@ class DynamicReplacementAttr final return ReplacedFunctionName; } + DeclNameLoc getReplacedFunctionNameLoc() const { + return ReplacedFunctionNameLoc; + } + /// Retrieve the location of the opening parentheses, if there is one. SourceLoc getLParenLoc() const; @@ -1752,6 +1760,7 @@ class SpecializeAttr final GenericSignature specializedSignature; DeclNameRef targetFunctionName; + DeclNameLoc targetFunctionNameLoc; LazyMemberLoader *resolver = nullptr; uint64_t resolverContextData; size_t numSPIGroups; @@ -1762,7 +1771,9 @@ class SpecializeAttr final SpecializeAttr(SourceLoc atLoc, SourceRange Range, TrailingWhereClause *clause, bool exported, SpecializationKind kind, GenericSignature specializedSignature, - DeclNameRef targetFunctionName, ArrayRef spiGroups, + DeclNameRef targetFunctionName, + DeclNameLoc targetFunctionNameLoc, + ArrayRef spiGroups, ArrayRef availabilityAttrs, size_t typeErasedParamsCount); @@ -1770,7 +1781,8 @@ class SpecializeAttr final static SpecializeAttr * create(ASTContext &Ctx, SourceLoc atLoc, SourceRange Range, TrailingWhereClause *clause, bool exported, SpecializationKind kind, - DeclNameRef targetFunctionName, ArrayRef spiGroups, + DeclNameRef targetFunctionName, DeclNameLoc targetFunctionNameLoc, + ArrayRef spiGroups, ArrayRef availabilityAttrs, GenericSignature specializedSignature = nullptr); @@ -1849,6 +1861,10 @@ class SpecializeAttr final return targetFunctionName; } + DeclNameLoc getTargetFunctionNameLoc() const { + return targetFunctionNameLoc; + } + /// \p forDecl is the value decl that the attribute belongs to. ValueDecl *getTargetFunctionDecl(const ValueDecl *forDecl) const; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index daf2caa87b0b1..c5a5a77d20e3d 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2995,11 +2995,10 @@ class ValueDecl : public Decl { return Name.getBaseIdentifier(); } - /// Generates a DeclNameRef referring to this declaration with as much - /// specificity as possible. - DeclNameRef createNameRef() const { - return DeclNameRef(Name); - } + /// Generates a DeclNameRef referring to this declaration. + /// + /// \param moduleSelector If true, the name ref includes the module name. + DeclNameRef createNameRef(bool moduleSelector = false) const; /// Retrieve the C declaration name that names this function, or empty /// string if it has none. diff --git a/include/swift/AST/DeclNameLoc.h b/include/swift/AST/DeclNameLoc.h index 494a4ae721faf..85dbb946c3108 100644 --- a/include/swift/AST/DeclNameLoc.h +++ b/include/swift/AST/DeclNameLoc.h @@ -35,61 +35,69 @@ class DeclNameLoc { /// Source location information. /// - /// If \c NumArgumentLabels == 0, this is the SourceLoc for the base name. - /// Otherwise, it points to an array of SourceLocs, which contains: + /// If \c NumArgumentLabels == 0 and \c !HasModuleSelectorLoc, this is the + /// SourceLoc for the base name. Otherwise, it points to an array of + /// SourceLocs, which contains: /// * The base name location + /// * The module selector location /// * The left parentheses location /// * The right parentheses location /// * The locations of each of the argument labels. const void *LocationInfo; /// The number of argument labels stored in the name. - unsigned NumArgumentLabels; + uint32_t NumArgumentLabels; + bool HasModuleSelectorLoc; enum { BaseNameIndex = 0, - LParenIndex = 1, - RParenIndex = 2, - FirstArgumentLabelIndex = 3, + ModuleSelectorIndex = 1, + LParenIndex = 2, + RParenIndex = 3, + FirstArgumentLabelIndex = 4, }; /// Retrieve a pointer to either the only source location that was /// stored or to the array of source locations that was stored. SourceLoc const * getSourceLocs() const { - if (NumArgumentLabels == 0) + if (NumArgumentLabels == 0 && !HasModuleSelectorLoc) return reinterpret_cast(&LocationInfo); return reinterpret_cast(LocationInfo); } - DeclNameLoc(const void *LocationInfo, unsigned NumArgumentLabels) - : LocationInfo(LocationInfo), NumArgumentLabels(NumArgumentLabels) {} + DeclNameLoc(const void *LocationInfo, unsigned NumArgumentLabels, + bool HasModuleSelectorLoc) + : LocationInfo(LocationInfo), NumArgumentLabels(NumArgumentLabels), + HasModuleSelectorLoc(HasModuleSelectorLoc) {} public: /// Create an invalid declaration name location. - DeclNameLoc() : DeclNameLoc(nullptr, 0) {} + DeclNameLoc() : DeclNameLoc(nullptr, 0, false) {} /// Create declaration name location information for a base name. explicit DeclNameLoc(SourceLoc baseNameLoc) - : DeclNameLoc(baseNameLoc.getOpaquePointerValue(), 0) {} + : DeclNameLoc(baseNameLoc.getOpaquePointerValue(), 0, false) {} explicit DeclNameLoc(ASTContext &ctx, SourceLoc moduleSelectorLoc, SourceLoc baseNameLoc) - : DeclNameLoc(baseNameLoc) { } + : DeclNameLoc(ctx, moduleSelectorLoc, baseNameLoc, + SourceLoc(), {}, SourceLoc()) { } /// Create declaration name location information for a compound /// name. DeclNameLoc(ASTContext &ctx, SourceLoc baseNameLoc, SourceLoc lParenLoc, ArrayRef argumentLabelLocs, - SourceLoc rParenLoc); + SourceLoc rParenLoc) + : DeclNameLoc(ctx, SourceLoc(), baseNameLoc, + lParenLoc, argumentLabelLocs, rParenLoc) { } DeclNameLoc(ASTContext &ctx, SourceLoc moduleSelectorLoc, SourceLoc baseNameLoc, SourceLoc lParenLoc, ArrayRef argumentLabelLocs, - SourceLoc rParenLoc) - : DeclNameLoc(ctx, baseNameLoc, lParenLoc, argumentLabelLocs, rParenLoc) { } + SourceLoc rParenLoc); /// Whether the location information is valid. bool isValid() const { return getBaseNameLoc().isValid(); } @@ -125,11 +133,12 @@ class DeclNameLoc { } SourceLoc getModuleSelectorLoc() const { - return SourceLoc(); + if (!HasModuleSelectorLoc) return SourceLoc(); + return getSourceLocs()[ModuleSelectorIndex]; } SourceLoc getStartLoc() const { - return getBaseNameLoc(); + return HasModuleSelectorLoc ? getModuleSelectorLoc() : getBaseNameLoc(); } SourceLoc getEndLoc() const { @@ -138,9 +147,7 @@ class DeclNameLoc { /// Retrieve the complete source range for this declaration name. SourceRange getSourceRange() const { - if (NumArgumentLabels == 0) return getBaseNameLoc(); - - return SourceRange(getBaseNameLoc(), getRParenLoc()); + return SourceRange(getStartLoc(), getEndLoc()); } }; diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 8d484ae855150..803ec973db03f 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -93,6 +93,21 @@ ERROR(forbidden_interpolated_string,none, ERROR(forbidden_extended_escaping_string,none, "%0 cannot be an extended escaping string literal", (StringRef)) +ERROR(expected_identifier_in_module_selector,none, + "expected identifier in module selector", ()) +ERROR(module_selector_not_allowed,none, + "%select{%error|%error|name in %1 declaration|captured variable name|" + "parameter name|generic parameter name|argument label|SPI group|" + "Objective-C name|name of sibling declaration|precedence group name|" + "attribute parameter value|%error}0 cannot be qualified with a module " + "selector", + (uint8_t, StringRef)) +NOTE(fixit_remove_module_selector,none, + "remove module selector from this name", ()) +NOTE(fixit_capture_with_explicit_name,none, + "explicitly capture into a variable named '%0'", + (StringRef)) + //------------------------------------------------------------------------------ // MARK: Lexer diagnostics //------------------------------------------------------------------------------ @@ -2183,5 +2198,9 @@ ERROR(nonisolated_nonsending_expected_rparen,PointsToFirstBadToken, ERROR(nonisolated_nonsending_repeated,none, "parameter may have at most one 'nonisolated(nonsending)' specifier", ()) +ERROR(impossible_parse,none, + "parser entered impossible state; please file a bug report with this " + "source file", ()) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 1c99d066ed8b9..a646d898cfd81 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1159,6 +1159,16 @@ ERROR(cannot_find_type_in_cast_expression,none, "type-casting operator expects a type on its right-hand side (got: %kind0)", (const ValueDecl *)) ERROR(cannot_find_type_in_scope_did_you_mean,none, "cannot find type %0 in scope; did you mean to use '%1'?", (DeclNameRef, StringRef)) +ERROR(type_not_in_module,none, + "type %0 is not imported through module %1", (DeclName, Identifier)) +ERROR(decl_not_in_module,none, + "declaration %0 is not imported through module %1", (DeclName, Identifier)) +NOTE(note_change_module_selector,none, + "did you mean module %0?", (Identifier)) +NOTE(note_remove_module_selector,none, + "did you mean the local declaration?", ()) +NOTE(note_add_explicit_self_with_module_selector,none, + "did you mean the member of 'self'?", ()) NOTE(note_typo_candidate_implicit_member,none, "did you mean the implicitly-synthesized %kindbase0?", (const ValueDecl *)) NOTE(note_remapped_type,none, diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index 7268aff1d1fbb..1f6d65fa60aab 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -682,39 +682,87 @@ void simple_display(llvm::raw_ostream &out, DeclName name); /// An in-source reference to another declaration, including qualification /// information. class DeclNameRef { - DeclName FullName; + friend class ASTContext; + + /// Contains the name and module for a DeclNameRef with a module selector. + struct alignas(Identifier) SelectiveDeclNameRef : llvm::FoldingSetNode { + Identifier moduleSelector; // Note: currently can never be empty(). + DeclName fullName; + + SelectiveDeclNameRef(Identifier moduleSelector, DeclName fullName) + : moduleSelector(moduleSelector), fullName(fullName) { } + + /// Uniquing for the ASTContext. + static void Profile(llvm::FoldingSetNodeID &id, Identifier moduleSelector, + DeclName fullName); + + void Profile(llvm::FoldingSetNodeID &id) { + Profile(id, moduleSelector, fullName); + } + + // Make vanilla new/delete illegal for SelectiveDeclNameRef. + void *operator new(size_t Bytes) = delete; + void operator delete(void *Data) = delete; + + // Only allow allocation of SelectiveDeclNameRef using the allocator + // in ASTContext or by doing a placement new. + void *operator new(size_t Bytes, const ASTContext &C, + unsigned Alignment = alignof(SelectiveDeclNameRef)); + void *operator new(size_t Bytes, void *Mem) { + assert(Mem); + return Mem; + } + }; + + llvm::PointerUnion storage; + + explicit DeclNameRef(void *Opaque) + : storage(decltype(storage)::getFromOpaqueValue(Opaque)) { } + + void initialize(ASTContext &C, Identifier moduleScope, DeclName fullName); public: static DeclNameRef createSubscript(); static DeclNameRef createConstructor(); + static DeclNameRef createSelf(const ASTContext &ctx); - DeclNameRef() : FullName() { } + DeclNameRef() : storage(DeclName()) { } - void *getOpaqueValue() const { return FullName.getOpaqueValue(); } + void *getOpaqueValue() const { + return storage.getOpaqueValue(); + } static DeclNameRef getFromOpaqueValue(void *p); explicit DeclNameRef(ASTContext &C, Identifier moduleSelector, - DeclName fullName) - : FullName(fullName) { } + DeclName fullName) { + initialize(C, moduleSelector, fullName); + } explicit DeclNameRef(ASTContext &C, Identifier moduleSelector, - DeclBaseName baseName, ArrayRef argLabels) - : FullName(C, baseName, argLabels) { } + DeclBaseName baseName, ArrayRef argLabels) { + initialize(C, moduleSelector, DeclName(C, baseName, argLabels)); + } explicit DeclNameRef(DeclName FullName) - : FullName(FullName) { } + : storage(FullName) { } bool hasModuleSelector() const { - return false; + return storage.is(); } Identifier getModuleSelector() const { - return Identifier(); + if (!hasModuleSelector()) + return Identifier(); + + return storage.get()->moduleSelector; } /// The name of the declaration being referenced. DeclName getFullName() const { - return FullName; + if (!hasModuleSelector()) + return storage.get(); + + return storage.get()->fullName; } /// The base name of the declaration being referenced. @@ -829,7 +877,7 @@ class DeclNameRef { }; inline DeclNameRef DeclNameRef::getFromOpaqueValue(void *p) { - return DeclNameRef(DeclName::getFromOpaqueValue(p)); + return DeclNameRef(p); } inline DeclNameRef DeclNameRef::withoutArgumentLabels(ASTContext &C) const { @@ -1013,7 +1061,7 @@ namespace llvm { static inline swift::DeclNameRef getFromVoidPointer(void *ptr) { return swift::DeclNameRef::getFromOpaqueValue(ptr); } - enum { NumLowBitsAvailable = PointerLikeTypeTraits::NumLowBitsAvailable }; + enum { NumLowBitsAvailable = PointerLikeTypeTraits::NumLowBitsAvailable - 1 }; }; // DeclNameRefs hash just like DeclNames. diff --git a/include/swift/AST/ModuleNameLookup.h b/include/swift/AST/ModuleNameLookup.h index 9713b8cffd88c..b8154c15e94c1 100644 --- a/include/swift/AST/ModuleNameLookup.h +++ b/include/swift/AST/ModuleNameLookup.h @@ -44,14 +44,14 @@ enum class ResolutionKind { void simple_display(llvm::raw_ostream &out, ResolutionKind kind); -/// Performs a lookup into the given module and it's imports. +/// Performs a lookup into the given module and its imports. /// -/// If 'moduleOrFile' is a ModuleDecl, we search the module and it's +/// If 'moduleOrFile' is a ModuleDecl, we search the module and its /// public imports. If 'moduleOrFile' is a SourceFile, we search the /// file's parent module, the module's public imports, and the source /// file's private imports. /// -/// \param moduleOrFile The module or file unit whose imports to search. +/// \param moduleOrFile The module or file unit to search, including imports. /// \param name The name to look up. /// \param[out] decls Any found decls will be added to this vector. /// \param lookupKind Whether this lookup is qualified or unqualified. diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index d678f9a7c3254..155a7ecad2add 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -33,7 +33,7 @@ namespace swift { class ASTContext; -class DeclName; +class DeclNameRef; class Type; class TypeDecl; class ValueDecl; @@ -486,6 +486,14 @@ class UsableFilteringDeclConsumer final : public VisibleDeclConsumer { /// \returns true if any declarations were removed, false otherwise. bool removeOverriddenDecls(SmallVectorImpl &decls); +/// Remove any declarations in the given set that do not match the +/// module selector, if it is not empty. +/// +/// \returns true if any declarations were removed, false otherwise. +bool removeOutOfModuleDecls(SmallVectorImpl &decls, + Identifier moduleSelector, + const DeclContext *dc); + /// Remove any declarations in the given set that are shadowed by /// other declarations in that set. /// @@ -561,6 +569,7 @@ void tryExtractDirectlyReferencedNominalTypes( /// Once name lookup has gathered a set of results, perform any necessary /// steps to prune the result set before returning it to the caller. void pruneLookupResultSet(const DeclContext *dc, NLOptions options, + Identifier moduleSelector, SmallVectorImpl &decls); /// Do nothing if debugClient is null. @@ -759,12 +768,12 @@ class ASTScope : public ASTAllocated { /// /// \param stopAfterInnermostBraceStmt If lookup should consider /// local declarations inside the innermost syntactic scope only. - static void lookupLocalDecls(SourceFile *, DeclName, SourceLoc, + static void lookupLocalDecls(SourceFile *, DeclNameRef, SourceLoc, bool stopAfterInnermostBraceStmt, ABIRole roleFilter, SmallVectorImpl &); - static void lookupLocalDecls(SourceFile *sf, DeclName name, SourceLoc loc, + static void lookupLocalDecls(SourceFile *sf, DeclNameRef name, SourceLoc loc, bool stopAfterInnermostBraceStmt, SmallVectorImpl &results) { lookupLocalDecls(sf, name, loc, stopAfterInnermostBraceStmt, @@ -772,7 +781,7 @@ class ASTScope : public ASTAllocated { } /// Returns the result if there is exactly one, nullptr otherwise. - static ValueDecl *lookupSingleLocalDecl(SourceFile *, DeclName, SourceLoc); + static ValueDecl *lookupSingleLocalDecl(SourceFile *, DeclNameRef, SourceLoc); /// Entry point to record the visible statement labels from the given /// point. diff --git a/include/swift/AST/NameLookupRequests.h b/include/swift/AST/NameLookupRequests.h index 36fe7b6974dbe..5da23e3ae9626 100644 --- a/include/swift/AST/NameLookupRequests.h +++ b/include/swift/AST/NameLookupRequests.h @@ -490,7 +490,21 @@ class LookupInModuleRequest private: friend SimpleRequest; - // Evaluation. + /// Performs a lookup into the given module and its imports. + /// + /// If 'moduleOrFile' is a ModuleDecl, we search the module and its + /// public imports. If 'moduleOrFile' is a SourceFile, we search the + /// file's parent module, the module's public imports, and the source + /// file's private imports. + /// + /// \param evaluator The request evaluator. + /// \param moduleOrFile The module or file unit to search, including imports. + /// \param name The name to look up. + /// \param lookupKind Whether this lookup is qualified or unqualified. + /// \param resolutionKind What sort of decl is expected. + /// \param moduleScopeContext The top-level context from which the lookup is + /// being performed, for checking access. This must be either a + /// FileUnit or a Module. QualifiedLookupResult evaluate(Evaluator &evaluator, const DeclContext *moduleOrFile, DeclName name, NLKind lookupKind, namelookup::ResolutionKind resolutionKind, diff --git a/include/swift/AST/TokenKinds.def b/include/swift/AST/TokenKinds.def index 11fc1469cb32d..f7cb378522b96 100644 --- a/include/swift/AST/TokenKinds.def +++ b/include/swift/AST/TokenKinds.def @@ -203,6 +203,7 @@ PUNCTUATOR(period_prefix, ".") PUNCTUATOR(comma, ",") PUNCTUATOR(ellipsis, "...") PUNCTUATOR(colon, ":") +PUNCTUATOR(colon_colon, "::") PUNCTUATOR(semi, ";") PUNCTUATOR(equal, "=") PUNCTUATOR(at_sign, "@") diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 6da0b8a8788b0..8d0fa8788788b 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -487,9 +487,8 @@ class Parser { /// \returns the value returned by \c f /// \note When calling, you may need to specify the \c Val type /// explicitly as a type parameter. - template - Val lookahead(unsigned char K, - llvm::function_ref f) { + template + decltype(auto) lookahead(unsigned char K, Fn f) { CancellableBacktrackingScope backtrackScope(*this); for (unsigned char i = 0; i < K; ++i) @@ -764,6 +763,17 @@ class Parser { consumeStartingCharacterOfCurrentToken(tok Kind = tok::oper_binary_unspaced, size_t Len = 1); + /// If the next token is \c tok::colon, consume it; if the next token is + /// \c tok::colon_colon, split it into two \c tok::colons and consume the + /// first; otherwise, do nothing and return false. + bool consumeIfColonSplittingDoubles() { + if (!Tok.isAny(tok::colon, tok::colon_colon)) + return false; + + consumeStartingCharacterOfCurrentToken(tok::colon); + return true; + } + //===--------------------------------------------------------------------===// // Primitive Parsing @@ -1055,7 +1065,7 @@ class Parser { std::optional &Exported, std::optional &Kind, TrailingWhereClause *&TrailingWhereClause, DeclNameRef &targetFunction, - AvailabilityRange *SILAvailability, + DeclNameLoc &targetFunctionLoc, AvailabilityRange *SILAvailability, SmallVectorImpl &spiGroups, SmallVectorImpl &availableAttrs, llvm::function_ref parseSILTargetName, @@ -1796,6 +1806,89 @@ class Parser { void parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc, bool isAttr = false); + /// The reason we are trying to parse a module selector. Other than + /// \c Allowed and \c InvalidOnly, all reasons indicate an error should be + /// emitted. + enum class ModuleSelectorReason : uint8_t { + /// Use of a module selector is allowed. + Allowed, + + /// Only parse (and diagnose) invalid module selectors here; if the module + /// selector is valid, return \c None and leave it for later. + InvalidOnly, + + /// Not allowed; this is the name of a declaration. The string parameter + /// describes the declaration in question (e.g. a class, struct, etc.). + /// + /// If a Decl subclass also cannot have its name prefixed at its use sites + /// (like ParamDecls), it will have a separate reason from this one. + NameInDecl, + + /// Not allowed; this the name of a variable being captured. Has a special + /// fix-it transforming `Mod::foo` into `foo = Mod::foo`. + Capture, + + /// Not allowed; this is the name of a parameter being declared. + ParamDecl, + + /// Not allowed; this is the name of a generic parameter being declared. + GenericParamDecl, + + /// Not allowed; this is an argument label at either a declaration or + /// use site. + ArgumentLabel, + + /// Not allowed; this is the name of an SPI group for the @_spi attribute. + SPIGroup, + + /// Not allowed; this is an Objective-C selector or class name, so it will + /// be used at runtime where the module selector would have no effect. + ObjCName, + + /// Not allowed; this is the name of a sibling to the current declaration + /// and has some kind of special contextual lookup. + /// + /// It may be possible to support module selectors on these in the future, + /// but at the moment these are all compiler-internal attributes and it + /// doesn't seem worth the effort. + SiblingDeclName, + + /// Not allowed; this is the name of a precedence group, either at its + /// declaration site (where it makes no sense to use a module selector) or + /// at a use site (where it might make sense, but is not currently + /// implemented). + PrecedenceGroup, + + /// Not allowed; this is a specially-handled keyword or identifier in an + /// attribute's argument list. + AttrParameter, + }; + + /// Attempts to parse a \c module-selector if one is present. + /// + /// \verbatim + /// module-selector: identifier '::' + /// \endverbatim + /// + /// At most use sites, this is actually called to parse a module selector + /// which should \em not be present in the source code, but which users might + /// plausibly write incorrectly. The \p reason argument indicates what the + /// name that is about to be parsed is, and therefore why there should not be + /// a module selector there. + /// + /// \param reason If not \c Allowed, gives a reason why a \c module-selector + /// should not be present in the source here. + /// \param declKindName For \c ModuleSelectorReason::NameInDecl, the kind of + /// declaration whose name we are parsing. Otherwise unused. + /// + /// \return \c None if no selector is present or a selector is present but + /// is not allowed; an instance with an empty \c Identifier if a + /// selector is present but has no valid identifier; an instance with + /// a valid \c Identifier if a selector is present and includes a + /// module name. + std::optional> + parseModuleSelector(ModuleSelectorReason reason, StringRef declKindName = ""); + enum class DeclNameFlag : uint8_t { /// If passed, operator basenames are allowed. AllowOperators = 1 << 0, @@ -1819,6 +1912,9 @@ class Parser { /// cases this doesn't actually make sense but we need to accept them for /// backwards compatibility. AllowLowercaseAndUppercaseSelf = 1 << 6, + + /// If passed, `$0` etc. are allowed. + AllowAnonymousParamNames = 1 << 7, }; using DeclNameOptions = OptionSet; @@ -1826,6 +1922,9 @@ class Parser { return DeclNameOptions(flag1) | flag2; } + /// Parse a declaration name that results in a `DeclNameRef` in the syntax + /// tree. + /// /// Without \c DeclNameFlag::AllowCompoundNames, parse an /// unqualified-decl-base-name. /// @@ -1836,8 +1935,9 @@ class Parser { /// unqualified-decl-name: /// unqualified-decl-base-name /// unqualified-decl-base-name '(' ((identifier | '_') ':') + ')' - DeclNameRef parseDeclNameRef(DeclNameLoc &loc, DiagRef diag, - DeclNameOptions flags); + DeclNameRef parseDeclNameRef( + DeclNameLoc &loc, DiagRef diag, DeclNameOptions flags, + ModuleSelectorReason modSelReason = ModuleSelectorReason::Allowed); /// Parse macro expansion. /// diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 159e5a86a2fba..e2103dc29c4dd 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -186,6 +186,10 @@ enum class FixKind : uint8_t { /// no access control. AllowInaccessibleMember, + /// If a module selector prevented us from selecting a member, pretend that it + /// was not specified. + AllowMemberFromWrongModule, + /// Allow KeyPaths to use AnyObject as root type AllowAnyObjectKeyPathRoot, @@ -1930,6 +1934,25 @@ class AllowInaccessibleMember final : public AllowInvalidMemberRef { } }; +class AllowMemberFromWrongModule final : public AllowInvalidMemberRef { + AllowMemberFromWrongModule(ConstraintSystem &cs, Type baseType, + ValueDecl *member, DeclNameRef name, + ConstraintLocator *locator) + : AllowInvalidMemberRef(cs, FixKind::AllowMemberFromWrongModule, baseType, + member, name, locator) {} + +public: + std::string getName() const override { + return "allow reference to member from wrong module"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + static AllowMemberFromWrongModule *create(ConstraintSystem &cs, Type baseType, + ValueDecl *member, DeclNameRef name, + ConstraintLocator *locator); +}; + class AllowAnyObjectKeyPathRoot final : public ConstraintFix { AllowAnyObjectKeyPathRoot(ConstraintSystem &cs, ConstraintLocator *locator) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index c23b4836bf360..c3d8ca97cdab3 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -2033,6 +2033,9 @@ struct MemberLookupResult { /// 'accesses' attributes of the init accessor and therefore canno /// t be referenced in its body. UR_UnavailableWithinInitAccessor, + + /// The module selector in the `DeclNameRef` does not match this candidate. + UR_WrongModule }; /// This is a list of considered (but rejected) candidates, along with a diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 3a1fc4f977f02..ca9c8faa4d2e9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -634,6 +634,7 @@ struct ASTContext::Implementation { llvm::FoldingSet BuiltinVectorTypes; llvm::FoldingSet BuiltinFixedArrayTypes; llvm::FoldingSet CompoundNames; + llvm::FoldingSet SelectiveNameRefs; llvm::DenseMap OpenedElementEnvironments; llvm::FoldingSet IndexSubsets; llvm::FoldingSet @@ -6148,6 +6149,44 @@ DeclName::DeclName(ASTContext &C, DeclBaseName baseName, initialize(C, baseName, names); } +// Only allow allocation of SelectiveDeclNameRefs using the allocator in +// ASTContext. +void *DeclNameRef::SelectiveDeclNameRef:: +operator new(size_t Bytes, const ASTContext &C, unsigned Alignment) { + return C.Allocate(Bytes, Alignment); +} + +void DeclNameRef::SelectiveDeclNameRef::Profile(llvm::FoldingSetNodeID &id, + Identifier moduleSelector, + DeclName fullName) { + assert(!moduleSelector.empty() && + "Looking up SelectiveDeclNameRef with empty module?"); + id.AddPointer(moduleSelector.getAsOpaquePointer()); + id.AddPointer(fullName.getOpaqueValue()); +} + +void DeclNameRef::initialize(ASTContext &C, Identifier moduleSelector, + DeclName fullName) { + if (moduleSelector.empty()) { + storage = fullName; + return; + } + + llvm::FoldingSetNodeID id; + SelectiveDeclNameRef::Profile(id, moduleSelector, fullName); + + void *insert = nullptr; + if (SelectiveDeclNameRef *selectiveRef + = C.getImpl().SelectiveNameRefs.FindNodeOrInsertPos(id, insert)) { + storage = selectiveRef; + return; + } + + auto selectiveRef = new (C) SelectiveDeclNameRef(moduleSelector, fullName); + storage = selectiveRef; + C.getImpl().SelectiveNameRefs.InsertNode(selectiveRef, insert); +} + /// Find the implementation of the named type in the given module. static NominalTypeDecl *findUnderlyingTypeInModule(ASTContext &ctx, Identifier name, diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 003b7ccb446da..78391b28ceef5 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -2080,10 +2080,11 @@ PrivateImportAttr *PrivateImportAttr::create(ASTContext &Ctxt, SourceLoc AtLoc, DynamicReplacementAttr::DynamicReplacementAttr(SourceLoc atLoc, SourceRange baseRange, DeclNameRef name, + DeclNameLoc nameLoc, SourceRange parenRange) : DeclAttribute(DeclAttrKind::DynamicReplacement, atLoc, baseRange, /*Implicit=*/false), - ReplacedFunctionName(name) { + ReplacedFunctionName(name), ReplacedFunctionNameLoc(nameLoc) { Bits.DynamicReplacementAttr.HasTrailingLocationInfo = true; getTrailingLocations()[0] = parenRange.Start; getTrailingLocations()[1] = parenRange.End; @@ -2092,11 +2093,12 @@ DynamicReplacementAttr::DynamicReplacementAttr(SourceLoc atLoc, DynamicReplacementAttr * DynamicReplacementAttr::create(ASTContext &Ctx, SourceLoc AtLoc, SourceLoc DynReplLoc, SourceLoc LParenLoc, - DeclNameRef ReplacedFunction, SourceLoc RParenLoc) { + DeclNameRef ReplacedFunction, + DeclNameLoc nameLoc, SourceLoc RParenLoc) { void *mem = Ctx.Allocate(totalSizeToAlloc(2), alignof(DynamicReplacementAttr)); return new (mem) DynamicReplacementAttr( - AtLoc, SourceRange(DynReplLoc, RParenLoc), ReplacedFunction, + AtLoc, SourceRange(DynReplLoc, RParenLoc), ReplacedFunction, nameLoc, SourceRange(LParenLoc, RParenLoc)); } @@ -2446,13 +2448,16 @@ SpecializeAttr::SpecializeAttr(SourceLoc atLoc, SourceRange range, SpecializationKind kind, GenericSignature specializedSignature, DeclNameRef targetFunctionName, + DeclNameLoc targetFunctionNameLoc, ArrayRef spiGroups, ArrayRef availableAttrs, size_t typeErasedParamsCount) : DeclAttribute(DeclAttrKind::Specialize, atLoc, range, /*Implicit=*/clause == nullptr), trailingWhereClause(clause), specializedSignature(specializedSignature), - targetFunctionName(targetFunctionName), numSPIGroups(spiGroups.size()), + targetFunctionName(targetFunctionName), + targetFunctionNameLoc(targetFunctionNameLoc), + numSPIGroups(spiGroups.size()), numAvailableAttrs(availableAttrs.size()), numTypeErasedParams(typeErasedParamsCount), typeErasedParamsInitialized(false) { @@ -2474,6 +2479,7 @@ SpecializeAttr *SpecializeAttr::create(ASTContext &Ctx, SourceLoc atLoc, TrailingWhereClause *clause, bool exported, SpecializationKind kind, DeclNameRef targetFunctionName, + DeclNameLoc targetFunctionNameLoc, ArrayRef spiGroups, ArrayRef availableAttrs, GenericSignature specializedSignature) { @@ -2499,7 +2505,8 @@ SpecializeAttr *SpecializeAttr::create(ASTContext &Ctx, SourceLoc atLoc, return new (mem) SpecializeAttr(atLoc, range, clause, exported, kind, specializedSignature, - targetFunctionName, spiGroups, availableAttrs, typeErasedParamsCount); + targetFunctionName, targetFunctionNameLoc, spiGroups, + availableAttrs, typeErasedParamsCount); } SpecializeAttr *SpecializeAttr::create(ASTContext &ctx, bool exported, @@ -2513,7 +2520,7 @@ SpecializeAttr *SpecializeAttr::create(ASTContext &ctx, bool exported, void *mem = ctx.Allocate(size, alignof(SpecializeAttr)); return new (mem) SpecializeAttr( SourceLoc(), SourceRange(), nullptr, exported, kind, specializedSignature, - targetFunctionName, spiGroups, availableAttrs, 0); + targetFunctionName, DeclNameLoc(), spiGroups, availableAttrs, 0); } SpecializeAttr *SpecializeAttr::create( @@ -2527,7 +2534,8 @@ SpecializeAttr *SpecializeAttr::create( void *mem = ctx.Allocate(size, alignof(SpecializeAttr)); auto *attr = new (mem) SpecializeAttr( SourceLoc(), SourceRange(), nullptr, exported, kind, specializedSignature, - targetFunctionName, spiGroups, availableAttrs, typeErasedParams.size()); + targetFunctionName, DeclNameLoc(), spiGroups, availableAttrs, + typeErasedParams.size()); attr->setTypeErasedParams(typeErasedParams); attr->resolver = resolver; attr->resolverContextData = data; diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index 6c67b7174bdc0..e60cea38243a8 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -322,11 +322,12 @@ BridgedDifferentiableAttr BridgedDifferentiableAttr_createParsed( BridgedDynamicReplacementAttr BridgedDynamicReplacementAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedSourceLoc cAttrNameLoc, BridgedSourceLoc cLParenLoc, - BridgedDeclNameRef cReplacedFunction, BridgedSourceLoc cRParenLoc) { + BridgedDeclNameRef cReplacedFunction, + BridgedDeclNameLoc cReplacedFunctionLoc, BridgedSourceLoc cRParenLoc) { return DynamicReplacementAttr::create( cContext.unbridged(), cAtLoc.unbridged(), cAttrNameLoc.unbridged(), cLParenLoc.unbridged(), cReplacedFunction.unbridged(), - cRParenLoc.unbridged()); + cReplacedFunctionLoc.unbridged(), cRParenLoc.unbridged()); } BridgedDocumentationAttr BridgedDocumentationAttr_createParsed( @@ -853,8 +854,8 @@ BridgedSpecializeAttr BridgedSpecializeAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedSourceRange cRange, BridgedNullableTrailingWhereClause cWhereClause, bool exported, BridgedSpecializationKind cKind, - BridgedDeclNameRef cTargetFunction, BridgedArrayRef cSPIGroups, - BridgedArrayRef cAvailableAttrs) { + BridgedDeclNameRef cTargetFunction, BridgedDeclNameLoc cTargetFunctionLoc, + BridgedArrayRef cSPIGroups, BridgedArrayRef cAvailableAttrs) { SmallVector spiGroups; for (auto bridging : cSPIGroups.unbridged()) spiGroups.push_back(bridging.unbridged()); @@ -865,7 +866,8 @@ BridgedSpecializeAttr BridgedSpecializeAttr_createParsed( return SpecializeAttr::create( cContext.unbridged(), cAtLoc.unbridged(), cRange.unbridged(), cWhereClause.unbridged(), exported, unbridge(cKind), - cTargetFunction.unbridged(), spiGroups, availableAttrs); + cTargetFunction.unbridged(), cTargetFunctionLoc.unbridged(), + spiGroups, availableAttrs); } BridgedSPIAccessControlAttr BridgedSPIAccessControlAttr_createParsed( @@ -918,4 +920,4 @@ BridgedUnavailableFromAsyncAttr BridgedUnavailableFromAsyncAttr_createParsed( return new (cContext.unbridged()) UnavailableFromAsyncAttr(cMessage.unbridged(), cAtLoc.unbridged(), cRange.unbridged(), /*implicit=*/false); -} \ No newline at end of file +} diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index eeeb02ee01f36..28bb51f19e2c1 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2868,6 +2868,14 @@ SourceRange TopLevelCodeDecl::getSourceRange() const { return Body? Body->getSourceRange() : SourceRange(); } +DeclNameRef ValueDecl::createNameRef(bool moduleSelector) const { + if (moduleSelector) + return DeclNameRef(getASTContext(), getModuleContext()->getName(), + getName()); + + return DeclNameRef(getName()); +} + static bool isPolymorphic(const AbstractStorageDecl *storage) { if (storage->shouldUseObjCDispatch()) return true; diff --git a/lib/AST/DeclNameLoc.cpp b/lib/AST/DeclNameLoc.cpp index 3c37eb5e0cb83..5e1b50c0a0dc4 100644 --- a/lib/AST/DeclNameLoc.cpp +++ b/lib/AST/DeclNameLoc.cpp @@ -20,16 +20,24 @@ using namespace swift; -DeclNameLoc::DeclNameLoc(ASTContext &ctx, SourceLoc baseNameLoc, +DeclNameLoc::DeclNameLoc(ASTContext &ctx, SourceLoc moduleSelectorLoc, + SourceLoc baseNameLoc, SourceLoc lParenLoc, ArrayRef argumentLabelLocs, SourceLoc rParenLoc) - : NumArgumentLabels(argumentLabelLocs.size()) { - assert(NumArgumentLabels > 0 && "Use other constructor"); + : NumArgumentLabels(argumentLabelLocs.size()), + HasModuleSelectorLoc(moduleSelectorLoc.isValid()) +{ + if (NumArgumentLabels == 0 && !HasModuleSelectorLoc) { + LocationInfo = baseNameLoc.getOpaquePointerValue(); + return; + } // Copy the location information into permanent storage. - auto storedLocs = ctx.Allocate(NumArgumentLabels + 3); + auto storedLocs = + ctx.Allocate(FirstArgumentLabelIndex + NumArgumentLabels); storedLocs[BaseNameIndex] = baseNameLoc; + storedLocs[ModuleSelectorIndex] = moduleSelectorLoc; storedLocs[LParenIndex] = lParenLoc; storedLocs[RParenIndex] = rParenLoc; std::memcpy(storedLocs.data() + FirstArgumentLabelIndex, diff --git a/lib/AST/Identifier.cpp b/lib/AST/Identifier.cpp index 0e32186ebdbee..39019e2010782 100644 --- a/lib/AST/Identifier.cpp +++ b/lib/AST/Identifier.cpp @@ -205,6 +205,10 @@ llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const { return print(os, /*skipEmptyArgumentNames=*/!isSpecial()); } +DeclNameRef DeclNameRef::createSelf(const ASTContext &ctx) { + return DeclNameRef(ctx.Id_self); +} + void DeclNameRef::dump() const { llvm::errs() << *this << "\n"; } diff --git a/lib/AST/ModuleNameLookup.cpp b/lib/AST/ModuleNameLookup.cpp index 288625bb5ab20..6bdcc094991cd 100644 --- a/lib/AST/ModuleNameLookup.cpp +++ b/lib/AST/ModuleNameLookup.cpp @@ -49,10 +49,21 @@ class ModuleNameLookup { resolutionKind(resolutionKind), respectAccessControl(!ctx.isAccessControlDisabled()) {} - /// Performs a qualified lookup into the given module and, if necessary, its - /// reexports. + /// Performs the qualified lookup requested by \p LookupStrategy into the + /// given module and, if necessary, its reexports. /// - /// The results are appended to \p decls. + /// If 'moduleOrFile' is a ModuleDecl, we search the module and it's + /// public imports. If 'moduleOrFile' is a SourceFile, we search the + /// file's parent module, the module's public imports, and the source + /// file's private imports. + /// + /// \param[out] decls Results are appended to this vector. + /// \param moduleOrFile The module or file unit to search, including imports. + /// \param accessPath The access path that was imported; if not empty, only + /// the named declaration will be imported. + /// \param moduleScopeContext The top-level context from which the lookup is + /// being performed, for checking access. This must be either a + /// FileUnit or a Module. void lookupInModule(SmallVectorImpl &decls, const DeclContext *moduleOrFile, ImportPath::Access accessPath, @@ -75,6 +86,10 @@ class LookupByName : public ModuleNameLookup { const NLKind lookupKind; public: + /// \param ctx The AST context that the lookup will be performed in. + /// \param name The name that will be looked up. + /// \param lookupKind Whether this lookup is qualified or unqualified. + /// \param resolutionKind What sort of decl is expected. LookupByName(ASTContext &ctx, ResolutionKind resolutionKind, DeclName name, NLKind lookupKind) : Super(ctx, resolutionKind), name(name), @@ -87,6 +102,10 @@ class LookupByName : public ModuleNameLookup { return true; } + /// \param module The module to search for declarations in. + /// \param path The access path that was imported; if not empty, only the + /// named declaration will be imported. + /// \param[out] localDecls Results are appended to this vector. void doLocalLookup(ModuleDecl *module, ImportPath::Access path, OptionSet flags, SmallVectorImpl &localDecls) { diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index eed8b1a0b8990..33eb0f8bb28b8 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -361,6 +361,42 @@ enum class ConstructorComparison { Better, }; +bool swift::removeOutOfModuleDecls(SmallVectorImpl &decls, + Identifier moduleSelector, + const DeclContext *dc) { + if (moduleSelector.empty()) + return false; + + ASTContext &ctx = dc->getASTContext(); + + // FIXME: Should we look this up relative to dc? + // We'd need a new ResolutionKind. + // FIXME: How can we diagnose this? + ModuleDecl *visibleFrom = ctx.getLoadedModule(moduleSelector); + if (!visibleFrom) { + LLVM_DEBUG(llvm::dbgs() << "no module " << moduleSelector << "\n"); + decls.clear(); + return true; + } + + bool initialCount = decls.size(); + decls.erase( + std::remove_if(decls.begin(), decls.end(), [&](ValueDecl *decl) -> bool { + bool inScope = ctx.getImportCache().isImportedBy(decl->getModuleContext(), + visibleFrom); + + LLVM_DEBUG(decl->dumpRef(llvm::dbgs())); + LLVM_DEBUG(llvm::dbgs() << ": " << decl->getModuleContext()->getName() + << (inScope ? " is " : " is NOT ") + << "selected by " << visibleFrom->getName() + << "\n"); + + return !inScope; + }), + decls.end()); + return initialCount != decls.size(); +} + /// Determines whether \p ctor1 is a "better" initializer than \p ctor2. static ConstructorComparison compareConstructors(ConstructorDecl *ctor1, ConstructorDecl *ctor2, @@ -2466,14 +2502,17 @@ bool namelookup::isInABIAttr(SourceFile *sourceFile, SourceLoc loc) { } void namelookup::pruneLookupResultSet(const DeclContext *dc, NLOptions options, + Identifier moduleSelector, SmallVectorImpl &decls) { // If we're supposed to remove overridden declarations, do so now. if (options & NL_RemoveOverridden) removeOverriddenDecls(decls); // If we're supposed to remove shadowed/hidden declarations, do so now. - if (options & NL_RemoveNonVisible) + if (options & NL_RemoveNonVisible) { + removeOutOfModuleDecls(decls, moduleSelector, dc); removeShadowedDecls(decls, dc); + } ModuleDecl *M = dc->getParentModule(); filterForDiscriminator(decls, M->getDebugClient()); @@ -2785,7 +2824,7 @@ QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, } } - pruneLookupResultSet(DC, options, decls); + pruneLookupResultSet(DC, options, member.getModuleSelector(), decls); if (auto *debugClient = DC->getParentModule()->getDebugClient()) { debugClient->finishLookupInNominals(DC, typeDecls, member.getFullName(), options, decls); @@ -2837,7 +2876,7 @@ ModuleQualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, } } - pruneLookupResultSet(DC, options, decls); + pruneLookupResultSet(DC, options, member.getModuleSelector(), decls); if (auto *debugClient = DC->getParentModule()->getDebugClient()) { debugClient->finishLookupInModule(DC, module, member.getFullName(), @@ -2905,7 +2944,7 @@ AnyObjectLookupRequest::evaluate(Evaluator &evaluator, const DeclContext *dc, decls.push_back(decl); } - pruneLookupResultSet(dc, options, decls); + pruneLookupResultSet(dc, options, member.getModuleSelector(), decls); if (auto *debugClient = dc->getParentModule()->getDebugClient()) { debugClient->finishLookupInAnyObject(dc, member.getFullName(), options, decls); diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 51820b41a9ca8..74ffb8828b362 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -249,8 +249,9 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { } if (Loc.isValid() && DC->getParentSourceFile()) { - // Operator lookup is always global, for the time being. - if (!Name.isOperator()) + // Operator lookup is always global, for the time being. Unqualified lookups + // with module selectors always start at global scope. + if (!Name.isOperator() && !Name.hasModuleSelector()) lookInASTScopes(); } else { assert((DC->isModuleScopeContext() || !DC->getParentSourceFile()) && @@ -382,7 +383,8 @@ ValueDecl *UnqualifiedLookupFactory::lookupBaseDecl(const DeclContext *baseDC) c return nullptr; auto selfDecl = ASTScope::lookupSingleLocalDecl(DC->getParentSourceFile(), - DeclName(Ctx.Id_self), Loc); + DeclNameRef::createSelf(Ctx), + Loc); if (!selfDecl) { return nullptr; } @@ -471,11 +473,24 @@ void UnqualifiedLookupFactory::setAsideUnavailableResults( } void UnqualifiedLookupFactory::addImportedResults(const DeclContext *const dc) { + assert(dc); + using namespace namelookup; SmallVector CurModuleResults; auto resolutionKind = isOriginallyTypeLookup ? ResolutionKind::TypesOnly : isOriginallyMacroLookup ? ResolutionKind::MacrosOnly : ResolutionKind::Overloadable; + auto moduleToLookIn = dc; + if (Name.hasModuleSelector()) + // FIXME: Should we look this up relative to dc? + // We'd need a new ResolutionKind. + moduleToLookIn = + dc->getASTContext().getLoadedModule(Name.getModuleSelector()); + + // If we didn't find the module, it obviously can't have any results. + if (!moduleToLookIn) + return; + auto nlOptions = NL_UnqualifiedDefault; if (options.contains(Flags::IncludeUsableFromInline)) nlOptions |= NL_IncludeUsableFromInline; @@ -483,7 +498,7 @@ void UnqualifiedLookupFactory::addImportedResults(const DeclContext *const dc) { nlOptions |= NL_ExcludeMacroExpansions; if (options.contains(Flags::ABIProviding)) nlOptions |= NL_ABIProviding; - lookupInModule(dc, Name.getFullName(), CurModuleResults, + lookupInModule(moduleToLookIn, Name.getFullName(), CurModuleResults, NLKind::UnqualifiedLookup, resolutionKind, dc, Loc, nlOptions); @@ -893,14 +908,14 @@ namespace { class ASTScopeDeclConsumerForLocalLookup : public AbstractASTScopeDeclConsumer { - DeclName name; + DeclNameRef name; bool stopAfterInnermostBraceStmt; ABIRole roleFilter; SmallVectorImpl &results; public: ASTScopeDeclConsumerForLocalLookup( - DeclName name, bool stopAfterInnermostBraceStmt, + DeclNameRef name, bool stopAfterInnermostBraceStmt, ABIRole roleFilter, SmallVectorImpl &results) : name(name), stopAfterInnermostBraceStmt(stopAfterInnermostBraceStmt), roleFilter(roleFilter), results(results) {} @@ -911,6 +926,8 @@ class ASTScopeDeclConsumerForLocalLookup bool consume(ArrayRef values, NullablePtr baseDC) override { + if (name.hasModuleSelector()) return false; + for (auto *value: values) { bool foundMatch = false; if (auto *varDecl = dyn_cast(value)) { @@ -924,7 +941,7 @@ class ASTScopeDeclConsumerForLocalLookup }); } - if (!foundMatch && value->getName().matchesRef(name) + if (!foundMatch && value->getName().matchesRef(name.getFullName()) && hasCorrectABIRole(value)) results.push_back(value); } @@ -951,7 +968,7 @@ class ASTScopeDeclConsumerForLocalLookup /// Lookup that only finds local declarations and does not trigger /// interface type computation. -void ASTScope::lookupLocalDecls(SourceFile *sf, DeclName name, SourceLoc loc, +void ASTScope::lookupLocalDecls(SourceFile *sf, DeclNameRef name, SourceLoc loc, bool stopAfterInnermostBraceStmt, ABIRole roleFilter, SmallVectorImpl &results) { @@ -960,7 +977,7 @@ void ASTScope::lookupLocalDecls(SourceFile *sf, DeclName name, SourceLoc loc, ASTScope::unqualifiedLookup(sf, loc, consumer); } -ValueDecl *ASTScope::lookupSingleLocalDecl(SourceFile *sf, DeclName name, +ValueDecl *ASTScope::lookupSingleLocalDecl(SourceFile *sf, DeclNameRef name, SourceLoc loc) { SmallVector result; ASTScope::lookupLocalDecls(sf, name, loc, diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 1e8192ef7d22b..8985d2075d5a9 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -740,6 +740,7 @@ extension ASTGenVisitor { attrNameLoc: self.generateSourceLoc(node.attributeName), lParenLoc: self.generateSourceLoc(node.leftParen), replacedFunction: replacedFunction.name, + replacedFunctionLoc: replacedFunction.loc, rParenLoc: self.generateSourceLoc(node.rightParen) ) } @@ -1884,7 +1885,7 @@ extension ASTGenVisitor { var exported: Bool? var kind: BridgedSpecializationKind? = nil var whereClause: BridgedTrailingWhereClause? = nil - var targetFunction: BridgedDeclNameRef? = nil + var targetFunction: (name: BridgedDeclNameRef, loc: BridgedDeclNameLoc)? var spiGroups: [BridgedIdentifier] = [] var availableAttrs: [BridgedAvailableAttr] = [] @@ -1896,7 +1897,7 @@ extension ASTGenVisitor { if targetFunction != nil { // TODO: Diangose. } - targetFunction = self.generateDeclNameRef(declReferenceExpr: arg.declName).name + targetFunction = self.generateDeclNameRef(declReferenceExpr: arg.declName) case .specializeAvailabilityArgument(let arg): availableAttrs = self.generateAvailableAttr( atLoc: self.generateSourceLoc(arg.availabilityLabel), @@ -1960,7 +1961,8 @@ extension ASTGenVisitor { whereClause: whereClause.asNullable, exported: exported ?? false, kind: kind ?? .full, - taretFunction: targetFunction ?? BridgedDeclNameRef(), + targetFunction: targetFunction?.name ?? BridgedDeclNameRef(), + targetFunctionLoc: targetFunction?.loc ?? BridgedDeclNameLoc(), spiGroups: spiGroups.lazy.bridgedArray(in: self), availableAttrs: availableAttrs.lazy.bridgedArray(in: self) ) diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index a1e3b467e2f9a..495b7ca5fcd90 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -819,9 +819,12 @@ static bool isLeftBound(const char *tokBegin, const char *bufferBegin) { static bool isRightBound(const char *tokEnd, bool isLeftBound, const char *codeCompletionPtr) { switch (*tokEnd) { + case ':': // ':' is an expression separator; '::' is not + return tokEnd[1] == ':'; + case ' ': case '\r': case '\n': case '\t': // whitespace case ')': case ']': case '}': // closing delimiters - case ',': case ';': case ':': // expression separators + case ',': case ';': // expression separators return false; case '\0': @@ -2761,9 +2764,15 @@ void Lexer::lexImpl() { case ',': return formToken(tok::comma, TokStart); case ';': return formToken(tok::semi, TokStart); - case ':': return formToken(tok::colon, TokStart); case '\\': return formToken(tok::backslash, TokStart); + case ':': + if (CurPtr[0] == ':') { + CurPtr++; + return formToken(tok::colon_colon, TokStart); + } + return formToken(tok::colon, TokStart); + case '#': { // Try lex a raw string literal. auto *Diags = getTokenDiags(); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6f18c4f6429a0..cedb8c3247c8f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -564,8 +564,8 @@ bool Parser::parseSpecializeAttributeArguments( std::optional &Exported, std::optional &Kind, swift::TrailingWhereClause *&TrailingWhereClause, - DeclNameRef &targetFunction, AvailabilityRange *SILAvailability, - SmallVectorImpl &spiGroups, + DeclNameRef &targetFunction, DeclNameLoc &targetFunctionLoc, + AvailabilityRange *SILAvailability, SmallVectorImpl &spiGroups, SmallVectorImpl &availableAttrs, llvm::function_ref parseSILTargetName, llvm::function_ref parseSILSIPModule) { @@ -666,13 +666,13 @@ bool Parser::parseSpecializeAttributeArguments( } if (ParamLabel == "target") { if (!parseSILTargetName(*this)) { - DeclNameLoc loc; targetFunction = parseDeclNameRef( - loc, diag::attr_specialize_expected_function, + targetFunctionLoc, diag::attr_specialize_expected_function, DeclNameFlag::AllowZeroArgCompoundNames | DeclNameFlag::AllowKeywordsUsingSpecialNames | DeclNameFlag::AllowOperators | - DeclNameFlag::AllowLowercaseAndUppercaseSelf); + DeclNameFlag::AllowLowercaseAndUppercaseSelf, + ModuleSelectorReason::SiblingDeclName); } } if (ParamLabel == "spiModule") { @@ -688,6 +688,7 @@ bool Parser::parseSpecializeAttributeArguments( consumeToken(); return false; } + parseModuleSelector(ModuleSelectorReason::SPIGroup); auto text = Tok.getText(); spiGroups.push_back(Context.getIdentifier(text)); consumeToken(); @@ -881,12 +882,13 @@ bool Parser::parseSpecializeAttribute( TrailingWhereClause *trailingWhereClause = nullptr; DeclNameRef targetFunction; + DeclNameLoc targetFunctionLoc; SmallVector spiGroups; SmallVector availableAttrs; if (!parseSpecializeAttributeArguments( ClosingBrace, DiscardAttribute, exported, kind, trailingWhereClause, - targetFunction, SILAvailability, spiGroups, availableAttrs, - parseSILTargetName, parseSILSIPModule)) { + targetFunction, targetFunctionLoc, SILAvailability, spiGroups, + availableAttrs, parseSILTargetName, parseSILSIPModule)) { return false; } @@ -916,8 +918,8 @@ bool Parser::parseSpecializeAttribute( // Store the attribute. Attr = SpecializeAttr::create(Context, AtLoc, SourceRange(Loc, rParenLoc), trailingWhereClause, exported.value(), - kind.value(), targetFunction, spiGroups, - availableAttrs); + kind.value(), targetFunction, targetFunctionLoc, + spiGroups, availableAttrs); return true; } @@ -1116,7 +1118,8 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) { MemberNameLoc, diag::attr_implements_expected_member_name, DeclNameFlag::AllowZeroArgCompoundNames | DeclNameFlag::AllowOperators | - DeclNameFlag::AllowLowercaseAndUppercaseSelf); + DeclNameFlag::AllowLowercaseAndUppercaseSelf, + ModuleSelectorReason::SiblingDeclName); if (!MemberName) { Status.setIsParseError(); } @@ -1138,7 +1141,7 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) { return Status; } - // FIXME(ModQual): Reject module qualification on MemberName. + assert(MemberName.getModuleSelector().empty()); return ParserResult( ImplementsAttr::create(Context, AtLoc, SourceRange(Loc, rParenLoc), ProtocolType.get(), MemberName.getFullName(), @@ -1787,11 +1790,10 @@ void Parser::parseObjCSelector(SmallVector &Names, IsNullarySelector = true; while (true) { // Empty selector piece. - if (Tok.is(tok::colon)) { + if (consumeIfColonSplittingDoubles()) { Names.push_back(Identifier()); - NameLocs.push_back(Tok.getLoc()); + NameLocs.push_back(PreviousLoc); IsNullarySelector = false; - consumeToken(); continue; } @@ -1802,8 +1804,7 @@ void Parser::parseObjCSelector(SmallVector &Names, consumeToken(); // If we have a colon, consume it. - if (Tok.is(tok::colon)) { - consumeToken(); + if (consumeIfColonSplittingDoubles()) { IsNullarySelector = false; continue; } @@ -2421,7 +2422,8 @@ Parser::parseMacroRoleAttribute( (DeclNameFlag::AllowOperators | DeclNameFlag::AllowKeywords | DeclNameFlag::AllowKeywordsUsingSpecialNames | DeclNameFlag::AllowCompoundNames | - DeclNameFlag::AllowZeroArgCompoundNames)); + DeclNameFlag::AllowZeroArgCompoundNames), + ModuleSelectorReason::AttrParameter); if (!name) { status.setIsParseError(); return status; @@ -2498,6 +2500,8 @@ static std::optional parseSingleAttrOptionImpl( P.consumeToken(tok::code_complete); } + P.parseModuleSelector(Parser::ModuleSelectorReason::AttrParameter); + StringRef parsedName = P.Tok.getText(); if (!P.consumeIf(tok::identifier)) { P.diagnose(Loc, nonIdentifierDiagnostic); @@ -2972,6 +2976,8 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, return makeParserSuccess(); } + parseModuleSelector(ModuleSelectorReason::SPIGroup); + auto text = Tok.getText(); // An spi group name can be '_' as in @_spi(_), a specifier for implicit import of the SPI. // '_' in source code is represented as an empty identifier in AST so match the behavior @@ -3515,6 +3521,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc LParenLoc = consumeAttributeLParen(); DeclNameRef replacedFunction; + DeclNameLoc replacedFunctionLoc; { // Parse 'for'. if (Tok.getText() != "for") { @@ -3529,15 +3536,12 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, return makeParserSuccess(); } consumeToken(tok::colon); - { - DeclNameLoc loc; - replacedFunction = parseDeclNameRef( - loc, diag::attr_dynamic_replacement_expected_function, - DeclNameFlag::AllowZeroArgCompoundNames | - DeclNameFlag::AllowKeywordsUsingSpecialNames | - DeclNameFlag::AllowOperators | - DeclNameFlag::AllowLowercaseAndUppercaseSelf); - } + replacedFunction = parseDeclNameRef( + replacedFunctionLoc, diag::attr_dynamic_replacement_expected_function, + DeclNameFlag::AllowZeroArgCompoundNames | + DeclNameFlag::AllowKeywordsUsingSpecialNames | + DeclNameFlag::AllowOperators | + DeclNameFlag::AllowLowercaseAndUppercaseSelf); } // Parse the matching ')'. @@ -3551,7 +3555,8 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, DynamicReplacementAttr *attr = DynamicReplacementAttr::create( - Context, AtLoc, Loc, LParenLoc, replacedFunction, RParenLoc); + Context, AtLoc, Loc, LParenLoc, replacedFunction, replacedFunctionLoc, + RParenLoc); Attributes.add(attr); break; } @@ -4176,11 +4181,15 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, .warnUntilSwiftVersion(6); } + bool hasModuleSelector = Context.LangOpts.hasFeature(Feature::ModuleSelector) + && peekToken().is(tok::colon_colon); + // If this not an identifier, the attribute is malformed. if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_in) && Tok.isNot(tok::kw_inout) && - Tok.isNot(tok::kw_rethrows)) { + Tok.isNot(tok::kw_rethrows) && + !hasModuleSelector) { if (Tok.is(tok::code_complete)) { if (CodeCompletionCallbacks) { @@ -4201,7 +4210,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, // If the attribute follows the new representation, switch // over to the alternate parsing path. - std::optional DK = + std::optional DK = hasModuleSelector ? std::nullopt : DeclAttribute::getAttrKindFromString(Tok.getText()); if (DK == DeclAttrKind::Rethrows) { DK = DeclAttrKind::AtRethrows; @@ -4213,7 +4222,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, auto checkInvalidAttrName = [&](StringRef invalidName, StringRef correctName, DeclAttrKind kind, std::optional> diag = std::nullopt) { - if (!DK && Tok.getText() == invalidName) { + if (!DK && !hasModuleSelector && Tok.getText() == invalidName) { DK = kind; if (diag) { @@ -4277,7 +4286,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, DeclAttrKind::Preconcurrency, diag::attr_renamed_warning); - if (!DK && Tok.getText() == "warn_unused_result") { + if (!DK && !hasModuleSelector && Tok.getText() == "warn_unused_result") { // The behavior created by @warn_unused_result is now the default. Emit a // Fix-It to remove. SourceLoc attrLoc = consumeToken(); @@ -4352,9 +4361,10 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, return parseNewDeclAttribute(Attributes, AtLoc, *DK, isFromClangAttribute); } - if (TypeAttribute::getAttrKindFromString(Tok.getText()).has_value()) + if (!hasModuleSelector && + TypeAttribute::getAttrKindFromString(Tok.getText()).has_value()) diagnose(Tok, diag::type_attribute_applied_to_decl); - else if (Tok.isContextualKeyword("unknown")) { + else if (!hasModuleSelector && Tok.isContextualKeyword("unknown")) { diagnose(Tok, diag::unknown_attr_name, "unknown"); } else { // Change the context to create a custom attribute syntax. @@ -6574,7 +6584,9 @@ ParserResult Parser::parseDeclImport(ParseDeclOptions Flags, .fixItRemove(Tok.getLoc()); return nullptr; } - HasNext = consumeIf(tok::period); + HasNext = consumeIf(tok::period) || + (Context.LangOpts.hasFeature(Feature::ModuleSelector) && + consumeIf(tok::colon_colon)); } while (HasNext); if (Tok.is(tok::code_complete)) { @@ -6705,6 +6717,8 @@ static ParserStatus parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, StringRef DeclKindName, llvm::function_ref canRecover) { + P.parseModuleSelector(Parser::ModuleSelectorReason::NameInDecl, DeclKindName); + if (P.Tok.is(tok::identifier)) { Loc = P.consumeIdentifier(Result, /*diagnoseDollarPrefix=*/true); @@ -7546,6 +7560,9 @@ static ParameterList *parseOptionalAccessorArgument(SourceLoc SpecifierLoc, // the default, not actually try to parse something. if (SpecifierLoc.isValid() && P.Tok.is(tok::l_paren)) { StartLoc = P.consumeToken(tok::l_paren); + + P.parseModuleSelector(Parser::ModuleSelectorReason::ParamDecl); + if (P.Tok.isNot(tok::identifier)) { P.diagnose(P.Tok, diag::expected_accessor_parameter_name, Kind == AccessorKind::Set ? 0 : @@ -10108,8 +10125,9 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, // designated protocol. These both look like identifiers, so we // parse them both as identifiers here and sort it out in type // checking. - SourceLoc colonLoc, groupLoc; - Identifier groupName; + SourceLoc colonLoc; + DeclNameLoc groupLoc; + DeclNameRef groupName; if (Tok.is(tok::colon)) { colonLoc = consumeToken(); if (Tok.is(tok::code_complete)) { @@ -10122,9 +10140,11 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, return makeParserCodeCompletionResult(); } - (void)parseIdentifier(groupName, groupLoc, - diag::operator_decl_expected_precedencegroup, - /*diagnoseDollarPrefix=*/false); + // TODO: We could support module selectors for precedence groups if we + // implemented the lookup for it. + groupName = parseDeclNameRef(groupLoc, + diag::operator_decl_expected_precedencegroup, + {}, ModuleSelectorReason::PrecedenceGroup); if (Context.TypeCheckerOpts.EnableOperatorDesignatedTypes) { // Designated types have been removed; consume the list (mainly for source @@ -10139,7 +10159,7 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, // These have no precedence group, so we already parsed the first entry // in the designated types list. Retroactively include it in the range. typesStartLoc = colonLoc; - typesEndLoc = groupLoc; + typesEndLoc = groupLoc.getEndLoc(); } while (Tok.isNot(tok::eof)) { @@ -10158,7 +10178,7 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, } else { if (isPrefix || isPostfix) { // If we have nothing after the colon, then just remove the colon. - auto endLoc = groupLoc.isValid() ? groupLoc : colonLoc; + auto endLoc = groupLoc.isValid() ? groupLoc.getEndLoc() : colonLoc; diagnose(colonLoc, diag::precedencegroup_not_infix) .fixItRemove({colonLoc, endLoc}); } @@ -10169,6 +10189,7 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, } // Diagnose deprecated operator body syntax `operator + { ... }`. + SourceLoc lastGoodLoc = PreviousLoc; SourceLoc lBraceLoc; if (consumeIf(tok::l_brace, lBraceLoc)) { if (isInfix && !Tok.is(tok::r_brace)) { @@ -10176,7 +10197,6 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, } else { auto Diag = diagnose(lBraceLoc, diag::deprecated_operator_body); if (Tok.is(tok::r_brace)) { - SourceLoc lastGoodLoc = groupLoc.isValid() ? groupLoc : NameLoc; SourceLoc lastGoodLocEnd = Lexer::getLocForEndOfToken(SourceMgr, lastGoodLoc); SourceLoc rBraceEnd = Lexer::getLocForEndOfToken(SourceMgr, Tok.getLoc()); @@ -10198,7 +10218,8 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, else res = new (Context) InfixOperatorDecl(CurDeclContext, OperatorLoc, Name, NameLoc, colonLoc, - groupName, groupLoc); + groupName.getBaseIdentifier(), + groupLoc.getBaseNameLoc()); diagnoseOperatorFixityAttributes(*this, Attributes, res); @@ -10218,6 +10239,8 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags, return nullptr; } + parseModuleSelector(ModuleSelectorReason::PrecedenceGroup); + Identifier name; SourceLoc nameLoc; if (parseIdentifier(name, nameLoc, /*diagnoseDollarPrefix=*/true, @@ -10417,14 +10440,17 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags, return abortBody(/*hasCodeCompletion*/true); } - if (Tok.isNot(tok::identifier)) { - diagnose(Tok, diag::expected_precedencegroup_relation, attrName); + DeclNameLoc nameLoc; + auto name = parseDeclNameRef(nameLoc, + { diag::expected_precedencegroup_relation, + attrName }, + {}, + ModuleSelectorReason::PrecedenceGroup); + if (!name) { return abortBody(); } - Identifier name; - SourceLoc nameLoc = consumeIdentifier(name, - /*diagnoseDollarPrefix=*/false); - relations.push_back({nameLoc, name, nullptr}); + relations.push_back({nameLoc.getBaseNameLoc(), name.getBaseIdentifier(), + nullptr}); if (skipUnspacedCodeCompleteToken()) return abortBody(/*hasCodeCompletion*/true); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 6b0ffdac82f14..40389468ad642 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -613,6 +613,9 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, /// '&' expr-unary(Mode) /// ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { + // If we have an invalid module selector, consume that first. + parseModuleSelector(ModuleSelectorReason::InvalidOnly); + UnresolvedDeclRefExpr *Operator; // First check to see if we have the start of a regex literal `/.../`. @@ -829,7 +832,8 @@ ParserResult Parser::parseExprKeyPathObjC() { // Parse the next name. DeclNameLoc nameLoc; DeclNameRef name = parseDeclNameRef(nameLoc, - diag::expr_keypath_expected_property_or_type, flags); + diag::expr_keypath_expected_property_or_type, flags, + ModuleSelectorReason::ObjCName); if (!name) { status.setIsParseError(); break; @@ -1269,6 +1273,8 @@ Parser::parseExprPostfixSuffix(ParserResult Result, bool isExprBasic, Tok.setKind(tok::period); consumeToken(); + parseModuleSelector(ModuleSelectorReason::InvalidOnly); + // Handle "x.42" - a tuple index. if (Tok.is(tok::integer_literal)) { DeclNameRef name(Context.getIdentifier(Tok.getText())); @@ -1640,6 +1646,9 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { /// expr-selector /// ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { + // If we have an invalid module selector, consume that first. + parseModuleSelector(ModuleSelectorReason::InvalidOnly); + switch (Tok.getKind()) { case tok::integer_literal: { StringRef Text = copyAndStripUnderscores(Tok.getText()); @@ -1724,6 +1733,9 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { // will be resolved (or rejected) by sema when the overall refutable pattern // it transformed from an expression into a pattern. if (canParseBindingInPattern) { + parseModuleSelector(ModuleSelectorReason::NameInDecl, + InBindingPattern.isLet() ? "constant" : "variable"); + Identifier name; SourceLoc loc = consumeIdentifier(name, /*diagnoseDollarPrefix=*/false); // If we have an inout/let/var, set that as our introducer. otherwise @@ -2135,14 +2147,29 @@ ParserResult Parser::parseExprStringLiteral() { AppendingExpr)); } +/// Equivalent to \c Tok.is(tok::colon), but pretends that \c tok::colon_colon +/// doesn't exist if \c EnableExperimentalModuleSelector is disabled. +static bool isColon(Parser &P, Token Tok, tok altColon = tok::NUM_TOKENS) { + // FIXME: Introducing tok::colon_colon broke diag::empty_arg_label_underscore. + // We only care about tok::colon_colon when module selectors are turned on, so + // when they are turned off, this function works around the bug by treating + // tok::colon_colon as a synonym for tok::colon. However, the bug still exists + // when Feature::ModuleSelector is enabled. We will need to address this + // before the feature can be released. + + if (P.Context.LangOpts.hasFeature(Feature::ModuleSelector)) + return Tok.isAny(tok::colon, altColon); + + return Tok.isAny(tok::colon, tok::colon_colon, altColon); +} + void Parser::parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc, bool isAttr) { /// A token that has the same meaning as colon, but is deprecated, if one exists for this call. auto altColon = isAttr ? tok::equal : tok::NUM_TOKENS; // Check to see if there is an argument label. - if (Tok.canBeArgumentLabel() && peekToken().isAny(tok::colon, altColon)) { - // Label found, including colon. + if (Tok.canBeArgumentLabel() && isColon(*this, peekToken(), altColon)) { auto text = Tok.getText(); // If this was an escaped identifier that need not have been escaped, say @@ -2161,7 +2188,7 @@ void Parser::parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc, } loc = consumeArgumentLabel(name, /*diagnoseDollarPrefix=*/false); - } else if (Tok.isAny(tok::colon, altColon)) { + } else if (isColon(*this, Tok, altColon)) { // Found only the colon. diagnose(Tok, diag::expected_label_before_colon) .fixItInsert(Tok.getLoc(), "<#label#>"); @@ -2171,7 +2198,12 @@ void Parser::parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc, } // If we get here, we ought to be on the colon. - assert(Tok.isAny(tok::colon, altColon)); + ASSERT(Tok.isAny(tok::colon, tok::colon_colon, altColon)); + + if (Tok.is(tok::colon_colon)) { + consumeIfColonSplittingDoubles(); + return; + } if (Tok.is(altColon)) diagnose(Tok, diag::replace_equal_with_colon_for_value) @@ -2201,7 +2233,7 @@ static bool tryParseArgLabelList(Parser &P, Parser::DeclNameOptions flags, flags.contains(Parser::DeclNameFlag::AllowZeroArgCompoundNames) && next.is(tok::r_paren); // An argument label. - bool nextIsArgLabel = next.canBeArgumentLabel() || next.is(tok::colon); + bool nextIsArgLabel = next.canBeArgumentLabel() || isColon(P, next); // An editor placeholder. bool nextIsPlaceholder = Identifier::isEditorPlaceholder(next.getText()); @@ -2214,11 +2246,11 @@ static bool tryParseArgLabelList(Parser &P, Parser::DeclNameOptions flags, lparenLoc = P.consumeToken(tok::l_paren); while (P.Tok.isNot(tok::r_paren)) { // If we see a ':', the user forgot the '_'; - if (P.Tok.is(tok::colon)) { - P.diagnose(P.Tok, diag::empty_arg_label_underscore) - .fixItInsert(P.Tok.getLoc(), "_"); + if (P.consumeIfColonSplittingDoubles()) { + P.diagnose(P.PreviousLoc, diag::empty_arg_label_underscore) + .fixItInsert(P.PreviousLoc, "_"); argumentLabels.push_back(Identifier()); - argumentLabelLocs.push_back(P.consumeToken(tok::colon)); + argumentLabelLocs.push_back(P.PreviousLoc); } Identifier argName; @@ -2244,9 +2276,86 @@ static bool tryParseArgLabelList(Parser &P, Parser::DeclNameOptions flags, return true; } +std::optional> Parser:: +parseModuleSelector(ModuleSelectorReason reason, StringRef declKindName) { + if (!Context.LangOpts.hasFeature(Feature::ModuleSelector)) + return std::nullopt; + + // Also allow the current token to be colon_colon, for diagnostics. + if (peekToken().isNot(tok::colon_colon) && Tok.isNot(tok::colon_colon)) + return std::nullopt; + + // Leave these paired tokens to be diagnosed by a future call to + // `parseModuleSelector()` at the next token, rather than consuming them as + // malformed module names and causing more errors later in the parser. + if (Tok.isAny(tok::l_paren, tok::l_brace, tok::l_angle, tok::l_square, + tok::r_paren, tok::r_brace, tok::r_angle, tok::r_square)) + return std::nullopt; + + // We will parse the selector whether or not it's allowed, then early return + // if it's disallowed, then diagnose any other errors in what we parsed. This + // will make sure we always consume the module selector's tokens, but don't + // complain about a malformed selector when it's not supposed to be there at + // all. + + SourceLoc nameLoc; + Identifier moduleName; + if (Tok.is(tok::identifier)) { + // If we are only supposed to consume invalid selectors, leave this for + // later. + if (reason == ModuleSelectorReason::InvalidOnly) { + return std::nullopt; + } + + nameLoc = consumeIdentifier(moduleName, /*diagnoseDollarPrefix=*/true); + } + else if (Tok.is(tok::colon_colon)) + // Let nameLoc and colonColonLoc both point to the tok::colon_colon. + nameLoc = Tok.getLoc(); + else + nameLoc = consumeToken(); + + auto colonColonLoc = consumeToken(tok::colon_colon); + + if (reason != ModuleSelectorReason::Allowed && + reason != ModuleSelectorReason::InvalidOnly) { + diagnose(colonColonLoc, diag::module_selector_not_allowed, + (uint8_t)reason, declKindName); + + // Special fix-it for capture lists which transforms `Mod::foo` into + // `foo = Mod::foo`. + if (reason == ModuleSelectorReason::Capture && + !moduleName.empty() && Tok.is(tok::identifier)) { + SmallString<32> scratch = Tok.getText(); + scratch += " = "; + diagnose(nameLoc, diag::fixit_capture_with_explicit_name, Tok.getText()) + .fixItInsert(nameLoc, scratch); + } + + diagnose(nameLoc, diag::fixit_remove_module_selector) + .fixItRemove({nameLoc, colonColonLoc}); + + return std::nullopt; + } + + if (moduleName.empty()) + diagnose(nameLoc, diag::expected_identifier_in_module_selector); + + return Located(moduleName, nameLoc); +} + DeclNameRef Parser::parseDeclNameRef(DeclNameLoc &loc, DiagRef diag, - DeclNameOptions flags) { + DeclNameOptions flags, + ModuleSelectorReason selectorReason) { + // Consume the module name, if present. + SourceLoc moduleSelectorLoc; + Identifier moduleSelector; + if (auto locatedModule = parseModuleSelector(selectorReason)) { + moduleSelectorLoc = locatedModule->Loc; + moduleSelector = locatedModule->Item; + } + // Consume the base name. DeclBaseName baseName; SourceLoc baseNameLoc; @@ -2256,6 +2365,10 @@ DeclNameRef Parser::parseDeclNameRef(DeclNameLoc &loc, Identifier baseNameId; baseNameLoc = consumeIdentifier(baseNameId, /*diagnoseDollarPrefix=*/false); baseName = baseNameId; + } else if (flags.contains(DeclNameFlag::AllowAnonymousParamNames) + && Tok.is(tok::dollarident)) { + baseName = Context.getIdentifier(Tok.getText()); + baseNameLoc = consumeToken(tok::dollarident); } else if (flags.contains(DeclNameFlag::AllowOperators) && Tok.isAnyOperator()) { baseName = Context.getIdentifier(Tok.getText()); @@ -2293,15 +2406,15 @@ DeclNameRef Parser::parseDeclNameRef(DeclNameLoc &loc, rparenLoc); if (argumentLabelLocs.empty() || !hadArgList) - loc = DeclNameLoc(baseNameLoc); + loc = DeclNameLoc(Context, moduleSelectorLoc, baseNameLoc); else - loc = DeclNameLoc(Context, baseNameLoc, lparenLoc, argumentLabelLocs, - rparenLoc); + loc = DeclNameLoc(Context, moduleSelectorLoc, baseNameLoc, + lparenLoc, argumentLabelLocs, rparenLoc); if (!hadArgList) - return DeclNameRef(baseName); + return DeclNameRef(Context, moduleSelector, baseName); - return DeclNameRef({ Context, baseName, argumentLabels }); + return DeclNameRef(Context, moduleSelector, baseName, argumentLabels); } ParserStatus Parser::parseFreestandingMacroExpansion( @@ -2320,7 +2433,8 @@ ParserStatus Parser::parseFreestandingMacroExpansion( bool hasWhitespaceBeforeName = poundEndLoc != Tok.getLoc(); - macroNameRef = parseDeclNameRef(macroNameLoc, diag, DeclNameFlag::AllowKeywords); + macroNameRef = parseDeclNameRef(macroNameLoc, diag, + DeclNameFlag::AllowKeywords); if (!macroNameRef) return makeParserError(); @@ -2590,9 +2704,23 @@ ParserStatus Parser::parseClosureSignatureIfPresent( // Okay, we have a closure signature. } else if (Tok.isIdentifierOrUnderscore() || Tok.is(tok::code_complete)) { - // Parse identifier (',' identifier)* + // Parse module-selector? identifier (',' module-selector? identifier)* + // The module selectors aren't legal, but we want to diagnose them if + // they're present. + if (Context.LangOpts.hasFeature(Feature::ModuleSelector) && + peekToken().is(tok::colon_colon)) { + consumeToken(); + consumeToken(tok::colon_colon); + } + consumeToken(); while (consumeIf(tok::comma)) { + if (Context.LangOpts.hasFeature(Feature::ModuleSelector) && + peekToken().is(tok::colon_colon)) { + consumeToken(); + consumeToken(tok::colon_colon); + } + if (Tok.isIdentifierOrUnderscore() || Tok.is(tok::code_complete)) { consumeToken(); continue; @@ -2666,8 +2794,10 @@ ParserStatus Parser::parseClosureSignatureIfPresent( } } else if (Tok.isAny(tok::identifier, tok::kw_self, tok::code_complete) && peekToken().isAny(tok::equal, tok::comma, tok::r_square, - tok::period)) { + tok::period, tok::colon_colon)) { // "x = 42", "x," and "x]" are all strong captures of x. + // "x::" is not permitted, but we want to diagnose it as though it were + // a strong capture. } else { diagnose(Tok, diag::expected_capture_specifier); skipUntil(tok::comma, tok::r_square); @@ -2682,10 +2812,17 @@ ParserStatus Parser::parseClosureSignatureIfPresent( // The thing being capture specified is an identifier, or as an identifier // followed by an expression. + Expr *initializer; Identifier name; SourceLoc nameLoc = Tok.getLoc(); SourceLoc equalLoc; + + // FIXME: It'd be nice to be able to capture with a module selector, but + // define a local name; however, that would complicate the equals check + // here. + parseModuleSelector(ModuleSelectorReason::Capture); + if (peekToken().isNot(tok::equal)) { // If this is the simple case, then the identifier is both the name and // the expression to capture. @@ -2782,6 +2919,8 @@ ParserStatus Parser::parseClosureSignatureIfPresent( const auto parameterListLoc = Tok.getLoc(); bool HasNext; do { + parseModuleSelector(ModuleSelectorReason::ParamDecl); + if (Tok.isNot(tok::identifier, tok::kw__, tok::code_complete)) { diagnose(Tok, diag::expected_closure_parameter_name); status.setIsParseError(); @@ -3040,8 +3179,14 @@ ParserResult Parser::parseExprClosure() { /// expr-anon-closure-argument: /// dollarident Expr *Parser::parseExprAnonClosureArg() { - StringRef Name = Tok.getText(); - SourceLoc Loc = consumeToken(tok::dollarident); + DeclNameLoc nameLoc; + DeclNameRef nameRef = + parseDeclNameRef(nameLoc, diag::impossible_parse, + DeclNameFlag::AllowAnonymousParamNames, + ModuleSelectorReason::ParamDecl); + + StringRef Name = nameRef.getBaseIdentifier().str(); + SourceLoc Loc = nameLoc.getBaseNameLoc(); assert(Name[0] == '$' && "Not a dollarident"); // We know from the lexer that this is all-numeric. @@ -3184,19 +3329,26 @@ Parser::parseArgumentList(tok leftTok, tok rightTok, bool isExprBasic, return makeParserResult(status, argList); } +/// See if we have an operator decl ref '()'. The operator token in +/// this case lexes as a binary operator because it neither leads nor +/// follows a proper subexpression. +bool listElementIsBinaryOperator(Parser &P, tok rightTok) { + // Look past a module selector, if present. + if (P.Tok.is(tok::identifier) && P.peekToken().is(tok::colon_colon)) { + return P.lookahead(2, [&](auto &scope) { + return listElementIsBinaryOperator(P, rightTok); + }); + } + + return P.Tok.isBinaryOperator() && P.peekToken().isAny(rightTok, tok::comma); +} + ParserStatus Parser::parseExprListElement(tok rightTok, bool isArgumentList, SourceLoc leftLoc, SmallVectorImpl &elts) { Identifier FieldName; SourceLoc FieldNameLoc; parseOptionalArgumentLabel(FieldName, FieldNameLoc); - // See if we have an operator decl ref '()'. The operator token in - // this case lexes as a binary operator because it neither leads nor - // follows a proper subexpression. - auto isUnappliedOperator = [&]() { - return Tok.isBinaryOperator() && peekToken().isAny(rightTok, tok::comma); - }; - - if (isUnappliedOperator()) { + if (listElementIsBinaryOperator(*this, rightTok)) { // Check to see if we have the start of a regex literal `/.../`. We need // to do this for an unapplied operator reference, as e.g `(/, /)` might // be a regex literal. @@ -3205,7 +3357,7 @@ ParserStatus Parser::parseExprListElement(tok rightTok, bool isArgumentList, Sou ParserStatus Status; Expr *SubExpr = nullptr; - if (isUnappliedOperator()) { + if (listElementIsBinaryOperator(*this, rightTok)) { DeclNameLoc Loc; auto OperName = parseDeclNameRef(Loc, diag::expected_operator_ref, diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index 265ba7cec0c82..854db24156381 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -76,6 +76,8 @@ Parser::parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, LetLoc = consumeToken(); } + parseModuleSelector(ModuleSelectorReason::GenericParamDecl); + // Parse the name of the parameter. Identifier Name; SourceLoc NameLoc; diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 2644052959abb..d36b9723b6bdd 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -122,7 +122,7 @@ bool Parser::startsParameterName(bool isClosure) { // contextual keywords, so look ahead one more token (two total) and see // if we have a ':' that would // indicate that this is an argument label. - return lookahead(2, [&](CancellableBacktrackingScope &) { + return lookahead(2, [&](CancellableBacktrackingScope &) { if (Tok.is(tok::colon)) return true; // isolated : @@ -170,6 +170,12 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, assert(params.empty() && leftParenLoc.isInvalid() && rightParenLoc.isInvalid() && "Must start with empty state"); + // Operators and closures cannot have API names. Enum elements cannot have + // internal names. + bool canHaveLabels = !(paramContext == ParameterContextKind::Operator || + paramContext == ParameterContextKind::Closure); + bool canHaveInternalName = paramContext != ParameterContextKind::EnumElement; + // Consume the starting '('; leftParenLoc = consumeToken(tok::l_paren); @@ -235,7 +241,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, // is this token the identifier of an argument label? `inout` is a // reserved keyword but the other modifiers are not. if (!Tok.is(tok::kw_inout)) { - bool partOfArgumentLabel = lookahead(1, [&](CancellableBacktrackingScope &) { + bool partOfArgumentLabel = lookahead(1, [&](CancellableBacktrackingScope &) { if (Tok.is(tok::colon)) return true; // isolated : @@ -344,22 +350,25 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, return parseType(diag::expected_parameter_type); }; + parseModuleSelector(canHaveLabels + ? ModuleSelectorReason::ArgumentLabel + : ModuleSelectorReason::ParamDecl); + if (startsParameterName(isClosure)) { // identifier-or-none for the first name param.FirstNameLoc = consumeArgumentLabel(param.FirstName, /*diagnoseDollarPrefix=*/!isClosure); + parseModuleSelector(ModuleSelectorReason::ParamDecl); + // identifier-or-none? for the second name if (Tok.canBeArgumentLabel()) param.SecondNameLoc = consumeArgumentLabel(param.SecondName, /*diagnoseDollarPrefix=*/true); - // Operators, closures, and enum elements cannot have API names. - if ((paramContext == ParameterContextKind::Operator || - paramContext == ParameterContextKind::Closure || - paramContext == ParameterContextKind::EnumElement) && - !param.FirstName.empty() && - param.SecondNameLoc.isValid()) { + // Do we have two names in a parameter that can't have both? + if (!(canHaveLabels && canHaveInternalName) && + !param.FirstName.empty() && param.SecondNameLoc.isValid()) { enum KeywordArgumentDiagnosticContextKind { Operator = 0, Closure = 1, @@ -1076,6 +1085,12 @@ ParserResult Parser::parseTypedPattern() { ParserResult Parser::parsePattern() { auto introducer = InBindingPattern.getIntroducer().value_or(VarDecl::Introducer::Let); + + // If there's a module selector here, consume and remove it. + StringRef declNameKind = introducer == VarDecl::Introducer::Let + ? "constant" : "variable"; + parseModuleSelector(ModuleSelectorReason::NameInDecl, declNameKind); + switch (Tok.getKind()) { case tok::l_paren: return parsePatternTuple(); @@ -1103,13 +1118,11 @@ ParserResult Parser::parsePattern() { SourceLoc loc = consumeIdentifier(name, /*diagnoseDollarPrefix=*/true); if (Tok.isIdentifierOrUnderscore() && !Tok.isContextualDeclKeyword() && !Tok.isAtStartOfLine()) - diagnoseConsecutiveIDs(name.str(), loc, - introducer == VarDecl::Introducer::Let - ? "constant" : "variable"); + diagnoseConsecutiveIDs(name.str(), loc, declNameKind); return makeParserResult(createBindingFromPattern(loc, name, introducer)); } - + case tok::code_complete: if (!CurDeclContext->isTypeContext()) { // This cannot be an overridden property, so just eat the token. We cannot @@ -1199,6 +1212,10 @@ Parser::parsePatternTupleElement() { Identifier Label; SourceLoc LabelLoc; + StringRef declNameKind = InBindingPattern.isLet() + ? "constant" : "variable"; + parseModuleSelector(ModuleSelectorReason::NameInDecl, declNameKind); + // If the tuple element has a label, parse it. if (Tok.is(tok::identifier) && peekToken().is(tok::colon)) { LabelLoc = consumeIdentifier(Label, /*diagnoseDollarPrefix=*/true); diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 18cfad4d45e5e..366349fd3b546 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -402,6 +402,9 @@ ParserResult Parser::parseSILBoxType(GenericParamList *generics, /// ParserResult Parser::parseTypeScalar( Diag<> MessageID, ParseTypeReason reason) { + // If we have an invalid module selector, consume that first. + parseModuleSelector(ModuleSelectorReason::InvalidOnly); + // Start a context for creating type syntax. ParserStatus status; @@ -1875,6 +1878,9 @@ bool Parser::canParseCollectionType() { } bool Parser::canParseTypeIdentifier() { + // Parse a module selector, if present. + parseModuleSelector(ModuleSelectorReason::Allowed); + // Parse an identifier. // // FIXME: We should expect e.g. 'X.var'. Almost any keyword is a valid member component. diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 09e66754859ce..11487e379dbd1 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7398,12 +7398,13 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, case ConversionRestrictionKind::CGFloatToDouble: case ConversionRestrictionKind::DoubleToCGFloat: { - DeclName name(ctx, DeclBaseName::createConstructor(), Identifier()); + // OK: Implicit conversion, no module selector to drop here. + DeclNameRef initRef(ctx, /*module selector=*/Identifier(), + DeclBaseName::createConstructor(), { Identifier() }); ConstructorDecl *decl = nullptr; SmallVector candidates; - dc->lookupQualified(toType->getAnyNominal(), - DeclNameRef(name), SourceLoc(), + dc->lookupQualified(toType->getAnyNominal(), initRef, SourceLoc(), NL_QualifiedDefault, candidates); for (auto *candidate : candidates) { auto *ctor = cast(candidate); diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 821a3168b4f5f..41ccd0091df8f 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1761,7 +1761,7 @@ class VarDeclMultipleReferencesChecker : public ASTWalker { if (name.isSimpleName(varDecl->getName()) && loc.isValid()) { auto *otherDecl = ASTScope::lookupSingleLocalDecl(DC->getParentSourceFile(), - name.getFullName(), loc); + name, loc); if (otherDecl == varDecl) ++count; } @@ -6322,10 +6322,7 @@ bool InaccessibleMemberFailure::diagnoseAsError() { if (baseExpr) { auto *locator = getConstraintLocator(baseExpr, ConstraintLocator::Member); - const auto &solution = getSolution(); - if (llvm::any_of(solution.Fixes, [&locator](const ConstraintFix *fix) { - return fix->getLocator() == locator; - })) + if (hasFixFor(getSolution(), locator)) return false; } @@ -6345,6 +6342,54 @@ bool InaccessibleMemberFailure::diagnoseAsError() { return true; } +bool MemberFromWrongModuleFailure::diagnoseAsError() { + auto anchor = getRawAnchor(); + // Let's try to avoid over-diagnosing chains of wrong-module + // members e.g.: + // + // struct A { + // struct B { + // struct C {} + // } + // } + // + // _ = A.Other::B.Other::C() + Expr *baseExpr = nullptr; + DeclNameLoc nameLoc; + if (auto *UDE = getAsExpr(anchor)) { + baseExpr = UDE->getBase(); + nameLoc = UDE->getNameLoc(); + } else if (auto *UME = getAsExpr(anchor)) { + nameLoc = UME->getNameLoc(); + } else if (auto *SE = getAsExpr(anchor)) { + baseExpr = SE->getBase(); + } else if (auto *call = getAsExpr(anchor)) { + baseExpr = call->getFn(); + } + + if (baseExpr) { + auto *locator = getConstraintLocator(baseExpr, ConstraintLocator::Member); + if (hasFixFor(getSolution(), locator)) + return false; + } + + auto modSelLoc = nameLoc.getModuleSelectorLoc(); + auto loc = nameLoc.isValid() ? nameLoc.getStartLoc() : ::getLoc(anchor); + + emitDiagnosticAt(loc, diag::decl_not_in_module, Member->getName(), + Name.getModuleSelector()); + + Identifier actualModuleName = Member->getModuleContext()->getName(); + assert(actualModuleName != Name.getModuleSelector() && + "Module selector failure on member in same module?"); + emitDiagnosticAt(loc, diag::note_change_module_selector, actualModuleName) + .fixItReplace(modSelLoc, actualModuleName.str()); + + emitDiagnosticAt(Member, diag::decl_declared_here, Member); + + return true; +} + SourceLoc AnyObjectKeyPathRootFailure::getLoc() const { auto anchor = getAnchor(); diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index ff1346f404091..be90241ae308a 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1644,6 +1644,27 @@ class InaccessibleMemberFailure final : public FailureDiagnostic { bool diagnoseAsError() override; }; +/// Diagnose an attempt to reference member from the wrong module with a module +/// selector, e.g. +/// +/// ```swift +/// import Foo +/// import Bar +/// +/// SomeType.Bar::methodDefinedInFoo() +/// ``` +class MemberFromWrongModuleFailure final : public FailureDiagnostic { + ValueDecl *Member; + DeclNameRef Name; + +public: + MemberFromWrongModuleFailure(const Solution &solution, DeclNameRef name, + ValueDecl *member, ConstraintLocator *locator) + : FailureDiagnostic(solution, locator), Member(member), Name(name) {} + + bool diagnoseAsError() override; +}; + /// Diagnose an attempt to reference member marked as `mutating` /// on immutable base e.g. `let` variable: /// diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 96e211a177592..f04ebdb0d0dc9 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1207,6 +1207,21 @@ AllowInaccessibleMember::create(ConstraintSystem &cs, Type baseType, AllowInaccessibleMember(cs, baseType, member, name, locator); } +bool AllowMemberFromWrongModule::diagnose(const Solution &solution, + bool asNote) const { + MemberFromWrongModuleFailure failure(solution, getMemberName(), getMember(), + getLocator()); + return failure.diagnose(asNote); +} + +AllowMemberFromWrongModule * +AllowMemberFromWrongModule::create(ConstraintSystem &cs, Type baseType, + ValueDecl *member, DeclNameRef name, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + AllowMemberFromWrongModule(cs, baseType, member, name, locator); +} + bool AllowAnyObjectKeyPathRoot::diagnose(const Solution &solution, bool asNote) const { AnyObjectKeyPathRootFailure failure(solution, getLocator()); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 69f17ad3dacc7..6a3c1ed56e77e 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -896,7 +896,7 @@ TypeVarRefCollector::walkToExprPre(Expr *expr) { auto loc = declRef->getLoc(); if (name.isSimpleName() && loc.isValid()) { auto *SF = CS.DC->getParentSourceFile(); - auto *D = ASTScope::lookupSingleLocalDecl(SF, name.getFullName(), loc); + auto *D = ASTScope::lookupSingleLocalDecl(SF, name, loc); inferTypeVars(D); } } @@ -3824,10 +3824,9 @@ namespace { componentTypeVars.push_back(memberTy); auto lookupName = kind == KeyPathExpr::Component::Kind::UnresolvedMember - ? DeclNameRef( - component.getUnresolvedDeclName()) // FIXME: type change - // needed - : component.getDeclRef().getDecl()->createNameRef(); + ? component.getUnresolvedDeclName() + : component.getDeclRef().getDecl()->createNameRef( + /*modSel=*/true); auto refKind = component.getFunctionRefInfo(); CS.addValueMemberConstraint(base, lookupName, memberTy, CurDC, @@ -5242,10 +5241,14 @@ ResolvedMemberResult swift::resolveValueMember(DeclContext &DC, Type BaseTy, ResolvedMemberResult Result; ConstraintSystem CS(&DC, std::nullopt); + // OK: By contract, `Name` should be derived from an existing Decl, not a + // name written by the user in source code. So when used as intended, we won't + // be dropping a module selector here. + DeclNameRef NameRef(Name); // Look up all members of BaseTy with the given Name. MemberLookupResult LookupResult = - CS.performMemberLookup(ConstraintKind::ValueMember, DeclNameRef(Name), - BaseTy, FunctionRefInfo::singleBaseNameApply(), + CS.performMemberLookup(ConstraintKind::ValueMember, NameRef, BaseTy, + FunctionRefInfo::singleBaseNameApply(), CS.getConstraintLocator({}), false); // Keep track of all the unviable members. diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 0bf0bbc04d54f..8b68786fa2a9b 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -8488,6 +8488,9 @@ ConstraintSystem::simplifyConstructionConstraint( // variable T. T2 is the result type provided via the construction // constraint itself. addValueMemberConstraint(MetatypeType::get(valueType, getASTContext()), + // OK: simplifyConstructionConstraint() is only used + // for `T(...)` init calls, not `T.init(...)` calls, + // so there's no module selector on `init`. DeclNameRef::createConstructor(), memberType, useDC, functionRefInfo, @@ -10109,8 +10112,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, // high. if (auto *args = getArgumentList(memberLocator)) { SmallVector scratch; - memberName.getFullName() = DeclName(ctx, memberName.getBaseName(), - args->getArgumentLabels(scratch)); + memberName = memberName.withArgumentLabels( + ctx, args->getArgumentLabels(scratch)); } } @@ -10757,8 +10760,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, } // If we have no viable or unviable candidates, and we're generating, - // diagnostics, rerun the query with inaccessible members included, so we can - // include them in the unviable candidates list. + // diagnostics, rerun the query with various excluded members included, so we + // can include them in the unviable candidates list. if (result.ViableCandidates.empty() && result.UnviableCandidates.empty() && includeInaccessibleMembers) { NameLookupOptions lookupOptions = @@ -10767,7 +10770,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, // Local function that looks up additional candidates using the given lookup // options, recording the results as unviable candidates. auto lookupUnviable = - [&](NameLookupOptions lookupOptions, + [&](DeclNameRef memberName, + NameLookupOptions lookupOptions, MemberLookupResult::UnviableReason reason) -> bool { auto lookup = TypeChecker::lookupMember(DC, instanceTy, memberName, memberLoc, lookupOptions); @@ -10791,9 +10795,20 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, return !lookup.empty(); }; + // Look for members that were excluded because of a module selector. + if (memberName.hasModuleSelector()) { + DeclNameRef unqualifiedMemberName{memberName.getFullName()}; + + if (lookupUnviable(unqualifiedMemberName, + lookupOptions, + MemberLookupResult::UR_WrongModule)) + return result; + } + // Ignore access control so we get candidates that might have been missed // before. - if (lookupUnviable(lookupOptions | NameLookupFlags::IgnoreAccessControl, + if (lookupUnviable(memberName, + lookupOptions | NameLookupFlags::IgnoreAccessControl, MemberLookupResult::UR_Inaccessible)) return result; } @@ -10994,6 +11009,11 @@ static ConstraintFix *fixMemberRef( : nullptr; } + case MemberLookupResult::UR_WrongModule: + assert(choice.isDecl()); + return AllowMemberFromWrongModule::create(cs, baseTy, choice.getDecl(), + memberName, locator); + case MemberLookupResult::UR_Inaccessible: assert(choice.isDecl()); return AllowInaccessibleMember::create(cs, baseTy, choice.getDecl(), @@ -15877,6 +15897,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AllowInvalidInitRef: case FixKind::AllowClosureParameterDestructuring: case FixKind::AllowInaccessibleMember: + case FixKind::AllowMemberFromWrongModule: case FixKind::AllowAnyObjectKeyPathRoot: case FixKind::AllowMultiArgFuncKeyPathMismatch: case FixKind::TreatKeyPathSubscriptIndexAsHashable: diff --git a/lib/Sema/PreCheckTarget.cpp b/lib/Sema/PreCheckTarget.cpp index f3cbbb2445a7f..79a97d2423546 100644 --- a/lib/Sema/PreCheckTarget.cpp +++ b/lib/Sema/PreCheckTarget.cpp @@ -558,8 +558,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, } } - DeclName lookupName(context, Name.getBaseName(), lookupLabels); - LookupName = DeclNameRef(lookupName); + LookupName = Name.withArgumentLabels(context, lookupLabels); } // Perform standard value name lookup. @@ -576,8 +575,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // First, look for a local binding in scope. if (Loc.isValid() && !Name.isOperator()) { - ASTScope::lookupLocalDecls(DC->getParentSourceFile(), - LookupName.getFullName(), Loc, + ASTScope::lookupLocalDecls(DC->getParentSourceFile(), LookupName, Loc, /*stopAfterInnermostBraceStmt=*/false, ResultValues); for (auto *localDecl : ResultValues) { @@ -637,6 +635,52 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, return errorResult(); } + // Is there an incorrect module selector? + if (Name.hasModuleSelector()) { + auto anyModuleName = DeclNameRef(LookupName.getFullName()); + auto anyModuleResults = TypeChecker::lookupUnqualified(DC, anyModuleName, + Loc, + lookupOptions); + if (!anyModuleResults.empty()) { + Context.Diags.diagnose(UDRE->getNameLoc(), diag::decl_not_in_module, + LookupName.getFullName(), + LookupName.getModuleSelector()); + + SourceLoc moduleSelectorLoc = UDRE->getNameLoc().getModuleSelectorLoc(); + + for (auto result : anyModuleResults) { + ValueDecl * decl = result.getValueDecl(); + Identifier moduleName = decl->getModuleContext()->getName(); + + if (moduleName != Name.getModuleSelector()) { + SmallString<64> replacement; + if (decl->isInstanceMember()) + replacement += "self."; + replacement += moduleName.str(); + + Context.Diags.diagnose(moduleSelectorLoc, + diag::note_change_module_selector, + moduleName) + .fixItReplace(moduleSelectorLoc, replacement); + } else { + // It's just something we need to pick up contextually. + if (decl->getDeclContext()->getLocalContext()) + decl->diagnose(diag::note_remove_module_selector) + .fixItRemoveChars(moduleSelectorLoc, + UDRE->getNameLoc().getBaseNameLoc()); + + if (decl->isInstanceMember()) + Context.Diags.diagnose(moduleSelectorLoc, + diag::note_add_explicit_self_with_module_selector) + .fixItInsert(moduleSelectorLoc, "self."); + } + } + + // FIXME: Can we recover by assuming the first/best result is correct? + return new (Context) ErrorExpr(UDRE->getSourceRange()); + } + } + // Try ignoring access control. NameLookupOptions relookupOptions = lookupOptions; relookupOptions |= NameLookupFlags::IgnoreAccessControl; @@ -2080,8 +2124,9 @@ VarDecl *PreCheckTarget::getImplicitSelfDeclForSuperContext(SourceLoc Loc) { // Do an actual lookup for 'self' in case it shows up in a capture list. auto *methodSelf = methodContext->getImplicitSelfDecl(); - auto *lookupSelf = ASTScope::lookupSingleLocalDecl(DC->getParentSourceFile(), - Ctx.Id_self, Loc); + auto *lookupSelf = ASTScope::lookupSingleLocalDecl( + DC->getParentSourceFile(), + DeclNameRef::createSelf(Ctx), Loc); if (lookupSelf && lookupSelf != methodSelf) { // FIXME: This is the wrong diagnostic for if someone manually declares a // variable named 'self' using backticks. diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 2edcc31fb553b..7ef2cc907b912 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -3164,10 +3164,11 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator, } CS.addDisjunctionConstraint(typeEqualityConstraints, locator); - CS.addValueMemberConstraint( - nominal->getInterfaceType(), DeclNameRef(context.Id_main), - Type(mainType), declContext, FunctionRefInfo::singleBaseNameApply(), {}, - locator); + CS.addValueMemberConstraint(nominal->getInterfaceType(), + DeclNameRef(context.Id_main), // OK: Generated + Type(mainType), declContext, + FunctionRefInfo::singleBaseNameApply(), {}, + locator); } FuncDecl *mainFunction = nullptr; @@ -3685,6 +3686,28 @@ static void lookupReplacedDecl(DeclNameRef replacedDeclName, results); } +static void +diagnoseCandidatesEliminatedByModuleSelector(DeclNameRefWithLoc replacedDeclName, + DeclAttribute *attr, + const ValueDecl *replacement, + DiagnosticEngine &Diags) { + if (replacedDeclName.Name.getModuleSelector().empty()) + return; + + // Look up without the module selector + SmallVector results; + lookupReplacedDecl(DeclNameRef(replacedDeclName.Name.getFullName()), + attr, replacement, results); + + auto selectorLoc = replacedDeclName.Loc.getModuleSelectorLoc(); + + for (auto candidate : results) + Diags.diagnose(selectorLoc, diag::note_change_module_selector, + candidate->getModuleContext()->getBaseIdentifier()) + .fixItReplace(selectorLoc, + candidate->getModuleContext()->getBaseIdentifier().str()); +} + /// Remove any argument labels from the interface type of the given value that /// are extraneous from the type system's point of view, producing the /// type to compare against for the purposes of dynamic replacement. @@ -3704,14 +3727,14 @@ static Type getDynamicComparisonType(ValueDecl *value) { return interfaceType->removeArgumentLabels(numArgumentLabels); } -static FuncDecl *findSimilarAccessor(DeclNameRef replacedVarName, +static FuncDecl *findSimilarAccessor(DeclNameRefWithLoc replacedVarName, const AccessorDecl *replacement, DeclAttribute *attr, ASTContext &ctx, bool forDynamicReplacement) { // Retrieve the replaced abstract storage decl. SmallVector results; - lookupReplacedDecl(replacedVarName, attr, replacement, results); + lookupReplacedDecl(replacedVarName.Name, attr, replacement, results); // Filter out any accessors that won't work. if (!results.empty()) { @@ -3744,15 +3767,19 @@ static FuncDecl *findSimilarAccessor(DeclNameRef replacedVarName, if (results.empty()) { Diags.diagnose(attr->getLocation(), diag::dynamic_replacement_accessor_not_found, - replacedVarName); + replacedVarName.Name); attr->setInvalid(); + + diagnoseCandidatesEliminatedByModuleSelector(replacedVarName, attr, + replacement, Diags); + return nullptr; } if (results.size() > 1) { Diags.diagnose(attr->getLocation(), diag::dynamic_replacement_accessor_ambiguous, - replacedVarName); + replacedVarName.Name); for (auto result : results) { Diags.diagnose(result, diag::dynamic_replacement_accessor_ambiguous_candidate, @@ -3794,7 +3821,7 @@ static FuncDecl *findSimilarAccessor(DeclNameRef replacedVarName, return origAccessor; } -static FuncDecl *findReplacedAccessor(DeclNameRef replacedVarName, +static FuncDecl *findReplacedAccessor(DeclNameRefWithLoc replacedVarName, const AccessorDecl *replacement, DeclAttribute *attr, ASTContext &ctx) { @@ -3802,7 +3829,7 @@ static FuncDecl *findReplacedAccessor(DeclNameRef replacedVarName, /*forDynamicReplacement*/ true); } -static FuncDecl *findTargetAccessor(DeclNameRef replacedVarName, +static FuncDecl *findTargetAccessor(DeclNameRefWithLoc replacedVarName, const AccessorDecl *replacement, DeclAttribute *attr, ASTContext &ctx) { @@ -3811,7 +3838,7 @@ static FuncDecl *findTargetAccessor(DeclNameRef replacedVarName, } static AbstractFunctionDecl * -findSimilarFunction(DeclNameRef replacedFunctionName, +findSimilarFunction(DeclNameRefWithLoc replacedFunctionName, const AbstractFunctionDecl *base, DeclAttribute *attr, DiagnosticEngine *Diags, bool forDynamicReplacement) { @@ -3819,7 +3846,7 @@ findSimilarFunction(DeclNameRef replacedFunctionName, // Any modification to attr must be guarded by a null check on TC. // SmallVector lookupResults; - lookupReplacedDecl(replacedFunctionName, attr, base, lookupResults); + lookupReplacedDecl(replacedFunctionName.Name, attr, base, lookupResults); SmallVector candidates; for (auto *result : lookupResults) { @@ -3840,7 +3867,9 @@ findSimilarFunction(DeclNameRef replacedFunctionName, forDynamicReplacement ? diag::dynamic_replacement_function_not_found : diag::specialize_target_function_not_found, - replacedFunctionName); + replacedFunctionName.Name); + diagnoseCandidatesEliminatedByModuleSelector(replacedFunctionName, attr, + base, *Diags); } attr->setInvalid(); @@ -3906,7 +3935,7 @@ findSimilarFunction(DeclNameRef replacedFunctionName, forDynamicReplacement ? diag::dynamic_replacement_function_of_type_not_found : diag::specialize_target_function_of_type_not_found, - replacedFunctionName, + replacedFunctionName.Name, base->getInterfaceType()->getCanonicalType()); for (auto *result : matches) { @@ -3922,7 +3951,7 @@ findSimilarFunction(DeclNameRef replacedFunctionName, } static AbstractFunctionDecl * -findReplacedFunction(DeclNameRef replacedFunctionName, +findReplacedFunction(DeclNameRefWithLoc replacedFunctionName, const AbstractFunctionDecl *replacement, DynamicReplacementAttr *attr, DiagnosticEngine *Diags) { return findSimilarFunction(replacedFunctionName, replacement, attr, Diags, @@ -3930,7 +3959,7 @@ findReplacedFunction(DeclNameRef replacedFunctionName, } static AbstractFunctionDecl * -findTargetFunction(DeclNameRef targetFunctionName, +findTargetFunction(DeclNameRefWithLoc targetFunctionName, const AbstractFunctionDecl *base, SpecializeAttr * attr, DiagnosticEngine *diags) { return findSimilarFunction(targetFunctionName, base, attr, diags, @@ -5588,13 +5617,15 @@ DynamicallyReplacedDeclRequest::evaluate(Evaluator &evaluator, } auto &Ctx = VD->getASTContext(); + DeclNameRefWithLoc nameWithLoc{attr->getReplacedFunctionName(), + attr->getReplacedFunctionNameLoc(), + std::nullopt}; if (auto *AD = dyn_cast(VD)) { - return findReplacedAccessor(attr->getReplacedFunctionName(), AD, attr, Ctx); + return findReplacedAccessor(nameWithLoc, AD, attr, Ctx); } if (auto *AFD = dyn_cast(VD)) { - return findReplacedFunction(attr->getReplacedFunctionName(), AFD, - attr, &Ctx.Diags); + return findReplacedFunction(nameWithLoc, AFD, attr, &Ctx.Diags); } if (auto *SD = dyn_cast(VD)) { @@ -5617,8 +5648,10 @@ SpecializeAttrTargetDeclRequest::evaluate(Evaluator &evaluator, auto &ctx = vd->getASTContext(); - auto targetFunctionName = attr->getTargetFunctionName(); - if (!targetFunctionName) + DeclNameRefWithLoc targetFunctionName{attr->getTargetFunctionName(), + attr->getTargetFunctionNameLoc(), + std::nullopt}; + if (!targetFunctionName.Name) return nullptr; if (auto *ad = dyn_cast(vd)) { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 0089ccc9da1a1..67de277b5189f 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -574,8 +574,8 @@ BodyInitKindRequest::evaluate(Evaluator &evaluator, auto loc = declRef->getLoc(); if (name.isSimpleName(ctx.Id_self)) { auto *otherSelfDecl = - ASTScope::lookupSingleLocalDecl(Decl->getParentSourceFile(), - name.getFullName(), loc); + ASTScope::lookupSingleLocalDecl(Decl->getParentSourceFile(), name, + loc); if (otherSelfDecl == Decl->getImplicitSelfDecl()) myKind = BodyInitKind::Delegating; } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index f7fef359f9466..5086836c6e523 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -754,7 +754,8 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current, else roleFilter = currentIsABIOnly ? ABIRole::ProvidesABI : ABIRole::ProvidesAPI; - ASTScope::lookupLocalDecls(currentFile, current->getBaseName(), + ASTScope::lookupLocalDecls(currentFile, + DeclNameRef(current->getBaseName()), current->getLoc(), /*stopAfterInnermostBraceStmt=*/true, roleFilter, otherDefinitions); diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 08d2eae7cf8fc..025ea8243ef0e 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -60,6 +60,7 @@ namespace { class LookupResultBuilder { LookupResult &Result; DeclContext *DC; + Identifier ModuleSelector; NameLookupOptions Options; /// The vector of found declarations. @@ -72,8 +73,9 @@ namespace { public: LookupResultBuilder(LookupResult &result, DeclContext *dc, - NameLookupOptions options) - : Result(result), DC(dc), Options(options) { + Identifier moduleSelector, NameLookupOptions options) + : Result(result), DC(dc), ModuleSelector(moduleSelector), Options(options) + { if (dc->getASTContext().isAccessControlDisabled()) Options |= NameLookupFlags::IgnoreAccessControl; } @@ -83,6 +85,11 @@ namespace { removeOverriddenDecls(FoundDecls); removeOverriddenDecls(FoundOuterDecls); + // Remove any declarations excluded by the module selector from the + // found-declarations set. + removeOutOfModuleDecls(FoundDecls, ModuleSelector, DC); + removeOutOfModuleDecls(FoundOuterDecls, ModuleSelector, DC); + // Remove any shadowed declarations from the found-declarations set. removeShadowedDecls(FoundDecls, DC); removeShadowedDecls(FoundOuterDecls, DC); @@ -290,7 +297,7 @@ LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclNameRef name, UnqualifiedLookupRequest{descriptor}, {}); LookupResult result; - LookupResultBuilder builder(result, dc, options); + LookupResultBuilder builder(result, dc, name.getModuleSelector(), options); for (auto idx : indices(lookup.allResults())) { const auto &found = lookup[idx]; // Determine which type we looked through to find this result. @@ -377,7 +384,7 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, // Make sure we've resolved implicit members, if we need them. namelookup::installSemanticMembersIfNeeded(type, name); - LookupResultBuilder builder(result, dc, options); + LookupResultBuilder builder(result, dc, name.getModuleSelector(), options); SmallVector lookupResults; dc->lookupQualified(type, name, loc, subOptions, lookupResults); diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 87e0a39c13651..dfe92ae9ab457 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -1573,8 +1573,9 @@ Pattern *TypeChecker::coercePatternToType( parentTy->getAnyNominal() == type->getAnyNominal()) { enumTy = type; } else { - diags.diagnose(EEP->getLoc(), diag::ambiguous_enum_pattern_type, - parentTy, type); + if (!type->hasError()) + diags.diagnose(EEP->getLoc(), diag::ambiguous_enum_pattern_type, + parentTy, type); return nullptr; } } @@ -1680,15 +1681,17 @@ Pattern *TypeChecker::coercePatternToType( Type elementType = type->getOptionalObjectType(); if (elementType.isNull()) { - auto diagID = diag::optional_element_pattern_not_valid_type; - SourceLoc loc = OP->getQuestionLoc(); - // Produce tailored diagnostic for if/let and other conditions. - if (OP->isImplicit()) { - diagID = diag::condition_optional_element_pattern_not_valid_type; - loc = OP->getLoc(); - } + if (!type->hasError()) { + auto diagID = diag::optional_element_pattern_not_valid_type; + SourceLoc loc = OP->getQuestionLoc(); + // Produce tailored diagnostic for if/let and other conditions. + if (OP->isImplicit()) { + diagID = diag::condition_optional_element_pattern_not_valid_type; + loc = OP->getLoc(); + } - diags.diagnose(loc, diagID, type); + diags.diagnose(loc, diagID, type); + } return nullptr; } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index db9c65f867202..644ec97b610b6 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1493,6 +1493,33 @@ static Type diagnoseUnknownType(const TypeResolution &resolution, return ErrorType::get(ctx); } + // Is there an incorrect module selector? + if (repr->getNameRef().hasModuleSelector()) { + auto anyModuleName = DeclNameRef(repr->getNameRef().getFullName()); + auto anyModuleResults = + TypeChecker::lookupUnqualifiedType(dc, anyModuleName, + repr->getLoc(), lookupOptions); + if (!anyModuleResults.empty()) { + diags.diagnose(repr->getNameLoc(), diag::type_not_in_module, + repr->getNameRef().getFullName(), + repr->getNameRef().getModuleSelector()); + + SourceLoc moduleSelectorLoc = repr->getNameLoc().getModuleSelectorLoc(); + + for (auto result : anyModuleResults) { + TypeDecl * decl = static_cast(result.getValueDecl()); + Identifier moduleName = decl->getModuleContext()->getName(); + + diags.diagnose(moduleSelectorLoc, diag::note_change_module_selector, + moduleName) + .fixItReplace(moduleSelectorLoc, moduleName.str()); + } + + // FIXME: Can we recover by assuming the first/best result is correct? + return ErrorType::get(ctx); + } + } + // Try ignoring access control. NameLookupOptions relookupOptions = lookupOptions; relookupOptions |= NameLookupFlags::IgnoreAccessControl; @@ -1584,6 +1611,32 @@ static Type diagnoseUnknownType(const TypeResolution &resolution, return ErrorType::get(ctx); } + // Is there an incorrect module selector? + if (repr->getNameRef().hasModuleSelector()) { + auto anyModuleName = DeclNameRef(repr->getNameRef().getFullName()); + auto anyModuleResults = TypeChecker::lookupMemberType( + dc, parentType, anyModuleName, repr->getLoc(), lookupOptions); + if (anyModuleResults) { + diags.diagnose(repr->getNameLoc(), diag::type_not_in_module, + repr->getNameRef().getFullName(), + repr->getNameRef().getModuleSelector()); + + SourceLoc moduleSelectorLoc = repr->getNameLoc().getModuleSelectorLoc(); + + for (auto result : anyModuleResults) { + TypeDecl * decl = result.Member; + Identifier moduleName = decl->getModuleContext()->getName(); + + diags.diagnose(moduleSelectorLoc, diag::note_change_module_selector, + moduleName) + .fixItReplace(moduleSelectorLoc, moduleName.str()); + } + + // FIXME: Can we recover by assuming the first/best result is correct? + return ErrorType::get(ctx); + } + } + // Try ignoring access control. NameLookupOptions relookupOptions = lookupOptions; relookupOptions |= NameLookupFlags::IgnoreAccessControl; diff --git a/test/NameLookup/Inputs/ModuleSelectorTestingKit.swiftinterface b/test/NameLookup/Inputs/ModuleSelectorTestingKit.swiftinterface new file mode 100644 index 0000000000000..631b3ecbf5898 --- /dev/null +++ b/test/NameLookup/Inputs/ModuleSelectorTestingKit.swiftinterface @@ -0,0 +1,42 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name ModuleSelectorTestingKit -swift-version 5 + +import Swift + +// These types are identical; we just use them to test with different scope +// selectors. + +public struct A { + public init(value: Swift.Int) + public dynamic mutating func negate() + public var magnitude: Swift.UInt +} + +public struct B { + public init(value: Swift.Int) + public dynamic mutating func negate() + public var magnitude: Swift.UInt +} + +public struct C { + public init(value: Int) + public dynamic mutating func negate() + public var magnitude: Swift.UInt +} + +public struct D { + public init(value: Int) + public dynamic mutating func negate() + public var magnitude: Swift.UInt +} + +@propertyWrapper +public struct available { + public init() {} + public var wrappedValue: Int { 0 } +} + +@_functionBuilder +public struct MyBuilder { + public static func buildBlock() +} diff --git a/test/NameLookup/module_selector.swift b/test/NameLookup/module_selector.swift index 0efc97316ec2c..04c23814bc445 100644 --- a/test/NameLookup/module_selector.swift +++ b/test/NameLookup/module_selector.swift @@ -1,3 +1,643 @@ -// RUN: %target-typecheck-verify-swift -enable-experimental-feature ModuleSelector +// RUN: %target-typecheck-verify-swift -sdk %clang-importer-sdk -module-name main -I %S/Inputs -enable-experimental-feature ModuleSelector + +// Make sure the lack of the experimental flag disables the feature: +// RUN: not %target-typecheck-verify-swift -sdk %clang-importer-sdk -module-name main -I %S/Inputs 2>/dev/null // REQUIRES: swift_feature_ModuleSelector + +// FIXME: This test doesn't really cover: +// +// * Whether X::foo finds foos in X's re-exports +// * Whether we handle access paths correctly +// * Interaction with ClangImporter +// * Cross-import overlays +// * Key paths +// * Key path dynamic member lookup +// * Custom type attributes (and coverage of type attrs generally is sparse) +// * Macros +// +// It also might not cover all combinations of name lookup paths and inputs. + +import ModuleSelectorTestingKit + +import ctypes::bits // FIXME: ban using :: with submodules? +import struct ModuleSelectorTestingKit::A + +let magnitude: Never = fatalError() + +// Test correct code using `A` + +extension ModuleSelectorTestingKit::A {} + +extension A: @retroactive Swift::Equatable { + @_implements(Swift::Equatable, ==(_:_:)) + public static func equals(_: ModuleSelectorTestingKit::A, _: ModuleSelectorTestingKit::A) -> Swift::Bool { + Swift::fatalError() + } + + // FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and + // @_derivative(of:) + + @_dynamicReplacement(for: ModuleSelectorTestingKit::negate()) + mutating func myNegate() { + let fn: (Swift::Int, Swift::Int) -> Swift::Int = (Swift::+) + + let magnitude: Int.Swift::Magnitude = main::magnitude + // expected-error@-1 {{cannot convert value of type 'Never' to specified type 'Int.Magnitude' (aka 'UInt')}} + + _ = (fn, magnitude) + + if Swift::Bool.Swift::random() { + self.ModuleSelectorTestingKit::negate() + } + else { + self = ModuleSelectorTestingKit::A(value: .Swift::min) + self = A.ModuleSelectorTestingKit::init(value: .min) + } + + self.main::myNegate() + + Swift::fatalError() + } + + // FIXME: Can we test @convention(witness_method:)? +} + +// Test resolution of main:: using `B` + +extension main::B {} +// expected-error@-1 {{type 'B' is not imported through module 'main'}} +// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{11-15=ModuleSelectorTestingKit}} + +extension B: @retroactive main::Equatable { + // expected-error@-1 {{type 'Equatable' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{27-31=Swift}} + + @_implements(main::Equatable, main::==(_:_:)) + // expected-error@-1 {{name of sibling declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{33-39=}} + // expected-error@-2 {{type 'Equatable' is not imported through module 'main'}} + // expected-note@-3 {{did you mean module 'Swift'?}} {{16-20=Swift}} + + public static func equals(_: main::B, _: main::B) -> main::Bool { + // expected-error@-1 2{{type 'B' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{32-36=ModuleSelectorTestingKit}} + // expected-note@-3 {{did you mean module 'ModuleSelectorTestingKit'?}} {{44-48=ModuleSelectorTestingKit}} + // expected-error@-4 {{type 'Bool' is not imported through module 'main'}} + // expected-note@-5 {{did you mean module 'Swift'?}} {{56-60=Swift}} + main::fatalError() // no-error -- not typechecking function bodies + } + + // FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and + // @_derivative(of:) + + @_dynamicReplacement(for: main::negate()) + // expected-error@-1 {{replaced function 'main::negate()' could not be found}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{29-33=ModuleSelectorTestingKit}} + + mutating func myNegate() { + let fn: (main::Int, main::Int) -> main::Int = + // expected-error@-1 3{{type 'Int' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{14-18=Swift}} + // expected-note@-3 {{did you mean module 'Swift'?}} {{25-29=Swift}} + // expected-note@-4 {{did you mean module 'Swift'?}} {{39-43=Swift}} + (main::+) + // FIXME: should fail???? + + let magnitude: Int.main::Magnitude = main::magnitude + // expected-error@-1 {{type 'Magnitude' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{24-28=Swift}} + + _ = (fn, magnitude) + + if main::Bool.main::random() { + // expected-error@-1 {{declaration 'Bool' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{8-12=Swift}} + + main::negate() + // expected-error@-1 {{declaration 'negate' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{7-11=self.ModuleSelectorTestingKit}} + } + else { + self = main::B(value: .main::min) + // expected-error@-1 {{declaration 'B' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{14-18=ModuleSelectorTestingKit}} + // expected-error@-3 {{cannot infer contextual base in reference to member 'main::min'}} + + self = B.main::init(value: .min) + // expected-error@-1 {{declaration 'init(value:)' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{16-20=ModuleSelectorTestingKit}} + } + + self.main::myNegate() + + main::fatalError() + // expected-error@-1 {{declaration 'fatalError' is not imported through module 'main'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{5-9=Swift}} + } + + // FIXME: Can we test @convention(witness_method:)? +} + +// Test resolution of ModuleSelectorTestingKit:: using `C` + +extension ModuleSelectorTestingKit::C {} + +extension C: @retroactive ModuleSelectorTestingKit::Equatable { + // expected-error@-1 {{type 'Equatable' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{27-51=Swift}} + + @_implements(ModuleSelectorTestingKit::Equatable, ModuleSelectorTestingKit::==(_:_:)) + // expected-error@-1 {{name of sibling declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{53-79=}} + // expected-error@-2 {{type 'Equatable' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-3 {{did you mean module 'Swift'?}} {{16-40=Swift}} + + public static func equals(_: ModuleSelectorTestingKit::C, _: ModuleSelectorTestingKit::C) -> ModuleSelectorTestingKit::Bool { + // expected-error@-1 {{type 'Bool' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{96-120=Swift}} + + ModuleSelectorTestingKit::fatalError() // no-error -- not typechecking function bodies + } + + // FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and + // @_derivative(of:) + + @_dynamicReplacement(for: ModuleSelectorTestingKit::negate()) + + mutating func myNegate() { + // expected-note@-1 {{'myNegate()' declared here}} + + let fn: (ModuleSelectorTestingKit::Int, ModuleSelectorTestingKit::Int) -> ModuleSelectorTestingKit::Int = + // expected-error@-1 3{{type 'Int' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{14-38=Swift}} + // expected-note@-3 {{did you mean module 'Swift'?}} {{45-69=Swift}} + // expected-note@-4 {{did you mean module 'Swift'?}} {{79-103=Swift}} + (ModuleSelectorTestingKit::+) + // FIXME: should fail???? + + let magnitude: Int.ModuleSelectorTestingKit::Magnitude = ModuleSelectorTestingKit::magnitude + // expected-error@-1 {{type 'Magnitude' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{24-48=Swift}} + + _ = (fn, magnitude) + + if ModuleSelectorTestingKit::Bool.ModuleSelectorTestingKit::random() { + // expected-error@-1 {{declaration 'Bool' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{8-32=Swift}} + + ModuleSelectorTestingKit::negate() + // expected-error@-1 {{declaration 'negate' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean the member of 'self'?}} {{7-7=self.}} + } + else { + self = ModuleSelectorTestingKit::C(value: .ModuleSelectorTestingKit::min) + // expected-error@-1 {{declaration 'min' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{50-74=Swift}} + + self = C.ModuleSelectorTestingKit::init(value: .min) + } + + self.ModuleSelectorTestingKit::myNegate() + // expected-error@-1 {{declaration 'myNegate()' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean module 'main'?}} {{10-34=main}} + + ModuleSelectorTestingKit::fatalError() + // expected-error@-1 {{declaration 'fatalError' is not imported through module 'ModuleSelectorTestingKit'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{5-29=Swift}} + } + + // FIXME: Can we test @convention(witness_method:)? +} + +// Test resolution of Swift:: using `D` + +extension Swift::D {} +// expected-error@-1 {{type 'D' is not imported through module 'Swift'}} +// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{11-16=ModuleSelectorTestingKit}} + +extension D: @retroactive Swift::Equatable { +// Caused by Swift::D failing to typecheck in `equals(_:_:)`: expected-error@-1 *{{extension outside of file declaring struct 'D' prevents automatic synthesis of '==' for protocol 'Equatable'}} expected-note@-1 *{{add stubs for conformance}} + + @_implements(Swift::Equatable, Swift::==(_:_:)) + // expected-error@-1 {{name of sibling declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{34-41=}} + + public static func equals(_: Swift::D, _: Swift::D) -> Swift::Bool { + // expected-error@-1 2{{type 'D' is not imported through module 'Swift'}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{32-37=ModuleSelectorTestingKit}} + // expected-note@-3 {{did you mean module 'ModuleSelectorTestingKit'?}} {{45-50=ModuleSelectorTestingKit}} + Swift::fatalError() // no-error -- not typechecking function bodies + } + + // FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and + // @_derivative(of:) + + @_dynamicReplacement(for: Swift::negate()) + // expected-error@-1 {{replaced function 'Swift::negate()' could not be found}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{29-34=ModuleSelectorTestingKit}} + + mutating func myNegate() { + // expected-note@-1 {{'myNegate()' declared here}} + + let fn: (Swift::Int, Swift::Int) -> Swift::Int = + (Swift::+) + + let magnitude: Int.Swift::Magnitude = Swift::magnitude + // expected-error@-1 {{declaration 'magnitude' is not imported through module 'Swift'}} + // expected-note@-2 {{did you mean module 'main'?}} {{43-48=main}} + + _ = (fn, magnitude) + + if Swift::Bool.Swift::random() { + + Swift::negate() + // expected-error@-1 {{declaration 'negate' is not imported through module 'Swift'}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{7-12=self.ModuleSelectorTestingKit}} + } + else { + self = Swift::D(value: .Swift::min) + // expected-error@-1 {{declaration 'D' is not imported through module 'Swift'}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{14-19=ModuleSelectorTestingKit}} + // expected-error@-3 {{cannot infer contextual base in reference to member 'Swift::min'}} + + self = D.Swift::init(value: .min) + // expected-error@-1 {{declaration 'init(value:)' is not imported through module 'Swift'}} + // expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{16-21=ModuleSelectorTestingKit}} + } + + self.Swift::myNegate() + // expected-error@-1 {{declaration 'myNegate()' is not imported through module 'Swift'}} + // expected-note@-2 {{did you mean module 'main'?}} {{10-15=main}} + + Swift::fatalError() + } + + // FIXME: Can we test @convention(witness_method:)? +} + +let mog: Never = fatalError() + +func localVarsCantBeAccessedByModuleSelector() { + let mag: Int.Swift::Magnitude = main::mag + // expected-error@-1 {{declaration 'mag' is not imported through module 'main'}} + // expected-note@-2 {{did you mean the local declaration?}} {{35-41=}} + + let mog: Never = main::mog +} + +struct AvailableUser { + @available(macOS 10.15, *) var use1: String { "foo" } + + @main::available() var use2 + // FIXME improve: expected-error@-1 {{unknown attribute 'available'}} + // FIXME suppress: expected-error@-2 {{type annotation missing in pattern}} + + @ModuleSelectorTestingKit::available() var use4 + // no-error + + @Swift::available() var use5 + // FIXME improve: expected-error@-1 {{unknown attribute 'available'}} + // FIXME suppress: expected-error@-2 {{type annotation missing in pattern}} +} + +func builderUser2(@main::MyBuilder fn: () -> Void) {} +// FIXME improve: expected-error@-1 {{unknown attribute 'MyBuilder'}} + +func builderUser3(@ModuleSelectorTestingKit::MyBuilder fn: () -> Void) {} +// no-error + +func builderUser4(@Swift::MyBuilder fn: () -> Void) {} +// FIXME improve: expected-error@-1 {{unknown attribute 'MyBuilder'}} + +func whitespace() { + _ = Swift::print + _ = Swift:: print + _ = Swift ::print + _ = Swift :: print + + _ = Swift:: + print + + _ = Swift + ::print + + _ = Swift :: + print + + _ = Swift + :: print + + _ = Swift + :: + print +} + +// Error cases + +func main::decl1( + // expected-error@-1 {{name in function declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{6-12=}} + main::p1: main::A, + // expected-error@-1 {{argument label cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{3-9=}} + // expected-error@-2 {{type 'A' is not imported through module 'main'}} + // expected-note@-3 {{did you mean module 'ModuleSelectorTestingKit'?}} {{13-17=ModuleSelectorTestingKit}} + main::label p2: main::inout A, + // expected-error@-1 {{argument label cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{3-9=}} + // FIXME: expected-error@-2 {{expected identifier in dotted type}} should be something like {{type 'inout' is not imported through module 'main'}} + label main::p3: @main::escaping () -> A + // expected-error@-1 {{parameter name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{9-15=}} + // FIXME: expected-error@-2 {{attribute can only be applied to declarations, not types}} should be something like {{type 'escaping' is not imported through module 'main'}} + // FIXME: expected-error@-3 {{expected parameter type following ':'}} +) { + let main::decl1a = "a" + // expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{7-13=}} + + var main::decl1b = "b" + // expected-error@-1 {{name in variable declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{7-13=}} + + let (main::decl1c, main::decl1d) = ("c", "d") + // expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{8-14=}} + // expected-error@-2 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-2 {{remove module selector from this name}} {{22-28=}} + + if let (main::decl1e, main::decl1f) = Optional(("e", "f")) {} + // expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{11-17=}} + // expected-error@-2 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-2 {{remove module selector from this name}} {{25-31=}} + + guard let (main::decl1g, main::decl1h) = Optional(("g", "h")) else { return } + // expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{14-20=}} + // expected-error@-2 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-2 {{remove module selector from this name}} {{28-34=}} + // From uses in the switch statements below: expected-note@-3 3 {{did you mean the local declaration?}} + + switch Optional(main::decl1g) { + // expected-error@-1 {{declaration 'decl1g' is not imported through module 'main'}} + case Optional.some(let main::decl1i): + // expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{26-32=}} + break + case .none: + break + } + + switch Optional(main::decl1g) { + // expected-error@-1 {{declaration 'decl1g' is not imported through module 'main'}} + case let Optional.some(main::decl1j): + // expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{26-32=}} + break + case .none: + break + } + + switch Optional(main::decl1g) { + // expected-error@-1 {{declaration 'decl1g' is not imported through module 'main'}} + case let main::decl1k?: + // expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{11-17=}} + break + case .none: + break + } + + for main::decl1l in "lll" {} + // expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{7-13=}} + + "lll".forEach { [main::magnitude] + // expected-error@-1 {{captured variable name cannot be qualified with a module selector}} + // expected-note@-2 {{remove module selector from this name}} {{20-26=}} + // expected-note@-3 {{explicitly capture into a variable named 'magnitude'}} {{20-20=magnitude = }} + main::elem in print(elem) + // expected-error@-1 {{parameter name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{5-11=}} + } + + "lll".forEach { (main::elem) in print(elem) } + // expected-error@-1 {{parameter name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{20-26=}} + + "lll".forEach { (main::elem) -> Void in print(elem) } + // expected-error@-1 {{parameter name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{20-26=}} + + "lll".forEach { (main::elem: Character) -> Void in print(elem) } + // expected-error@-1 {{parameter name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{20-26=}} +} +enum main::decl2 { + // expected-error@-1 {{name in enum declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{6-12=}} + + case main::decl2a + // expected-error@-1 {{name in enum 'case' declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{8-14=}} +} + +struct main::decl3 {} +// expected-error@-1 {{name in struct declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{8-14=}} + +class main::decl4 {} +// expected-error@-1 {{name in class declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{7-13=}} +// expected-error@-2 {{generic parameter name cannot be qualified with a module selector}} expected-note@-2 {{remove module selector from this name}} {{19-25=}} + +typealias main::decl5 = main::Bool +// expected-error@-1 {{name in typealias declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{11-17=}} +// expected-error@-2 {{type 'Bool' is not imported through module 'main'}} +// expected-note@-3 {{did you mean module 'Swift'?}} {{25-29=Swift}} + +protocol main::decl6 { + // expected-error@-1 {{name in protocol declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{10-16=}} + + associatedtype main::decl6a + // expected-error@-1 {{name in associatedtype declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{18-24=}} +} + +let main::decl7 = 7 +// expected-error@-1 {{name in constant declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{5-11=}} + +var main::decl8 = 8 { +// expected-error@-1 {{name in variable declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{5-11=}} + + willSet(main::newValue) {} + // expected-error@-1 {{parameter name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{11-17=}} + + didSet(main::oldValue) {} + // expected-error@-1 {{parameter name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{10-16=}} +} + +struct Parent { + func main::decl1() {} + // expected-error@-1 {{name in function declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{8-14=}} + + enum main::decl2 { + // expected-error@-1 {{name in enum declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{8-14=}} + + case main::decl2a + // expected-error@-1 {{name in enum 'case' declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{10-16=}} + } + + struct main::decl3 {} + // expected-error@-1 {{name in struct declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{10-16=}} + + class main::decl4 {} + // expected-error@-1 {{name in class declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{9-15=}} + + typealias main::decl5 = main::Bool + // expected-error@-1 {{name in typealias declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{13-19=}} + // expected-error@-2 {{type 'Bool' is not imported through module 'main'}} + // expected-note@-3 {{did you mean module 'Swift'?}} {{27-31=Swift}} +} + +@_swift_native_objc_runtime_base(main::BaseClass) +// expected-error@-1 {{attribute parameter value cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{34-40=}} +class C1 {} + +infix operator <<<<< : Swift::AdditionPrecedence +// expected-error@-1 {{precedence group name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{24-31=}} + +precedencegroup main::PG1 { +// expected-error@-1 {{precedence group name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{17-23=}} + + higherThan: Swift::AdditionPrecedence + // expected-error@-1 {{precedence group name cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{15-22=}} +} + +func badModuleNames() { + NonexistentModule::print() + // expected-error@-1 {{declaration 'print' is not imported through module 'NonexistentModule'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{3-20=Swift}} + // FIXME redundant: expected-note@-3 {{did you mean module 'Swift'?}} + + _ = "foo".NonexistentModule::count + // expected-error@-1 {{declaration 'count' is not imported through module 'NonexistentModule'}} + // expected-note@-2 {{did you mean module 'Swift'?}} {{13-30=Swift}} + + let x: NonexistentModule::MyType = NonexistentModule::MyType() + // expected-error@-1 {{cannot find type 'NonexistentModule::MyType' in scope}} + + let y: A.NonexistentModule::MyChildType = fatalError() + // expected-error@-1 {{'NonexistentModule::MyChildType' is not a member type of struct 'ModuleSelectorTestingKit.A'}} +} + +struct BadModuleSelectorSyntax { // expected-note {{in declaration of 'BadModuleSelectorSyntax'}} + var a: ::Int + // expected-error@-1 {{expected identifier in module selector}} + + var b: (::Int) + // expected-error@-1 {{expected identifier in module selector}} + + var c: *::Int + // expected-error@-1 {{expected identifier in module selector}} + + var d: _::Int + // expected-error@-1 {{expected identifier in module selector}} + + var e: Self::Int + // expected-error@-1 {{expected identifier in module selector}} + + var f: self::Int + // expected-error@-1 {{expected identifier in module selector}} + + var g: inout::Int + // expected-error@-1 {{expected identifier in module selector}} + + var h: Any::Int + // expected-error@-1 {{expected identifier in module selector}} + + var aArray: [::Int] + // expected-error@-1 {{expected identifier in module selector}} + + var bArray: [(::Int)] + // expected-error@-1 {{expected identifier in module selector}} + + var cArray: [*::Int] + // expected-error@-1 {{expected identifier in module selector}} + + var dArray: [_::Int] + // expected-error@-1 {{expected identifier in module selector}} + + var eArray: [Self::Int] + // expected-error@-1 {{expected identifier in module selector}} + + var fArray: [self::Int] + // expected-error@-1 {{expected identifier in module selector}} + + var gArray: [inout::Int] + // expected-error@-1 {{expected identifier in module selector}} + + var hArray: [Any::Int] + // expected-error@-1 {{expected identifier in module selector}} + + var aIndex: String.::Index + // expected-error@-1 {{expected identifier in module selector}} + + // FIXME: This gets interpreted as a single `.*` operator; may not be ideal. + var cIndex: String.*::Index + // expected-error@-1 {{consecutive declarations on a line must be separated by ';'}} + // expected-error@-2 {{expected declaration}} + + var dIndex: String._::Index + // expected-error@-1 {{expected identifier in module selector}} + + var eIndex: String.Self::Index + // expected-error@-1 {{expected identifier in module selector}} + + var fIndex: String.self::Index + // expected-error@-1 {{expected identifier in module selector}} + + var gIndex: String.inout::Index + // expected-error@-1 {{expected identifier in module selector}} + + var hIndex: String.Any::Index + // expected-error@-1 {{expected identifier in module selector}} + + func inExpr() { + ::print() + // expected-error@-1 {{expected identifier in module selector}} + + (::print()) + // expected-error@-1 {{expected identifier in module selector}} + + *::print() + // expected-error@-1 {{expected identifier in module selector}} + + _::print() + // expected-error@-1 {{expected identifier in module selector}} + + Self::print() + // expected-error@-1 {{expected identifier in module selector}} + + self::print() + // expected-error@-1 {{expected identifier in module selector}} + + inout::print() + // expected-error@-1 {{expected identifier in module selector}} + + Any::print() + // expected-error@-1 {{expected identifier in module selector}} + + _ = 1.::magnitude + // expected-error@-1 {{expected identifier in module selector}} + + _ = (1.::magnitude) + // expected-error@-1 {{expected identifier in module selector}} + + // FIXME: This gets interpreted as a single `.*` operator; may not be ideal. + _ = 1.*::magnitude + // expected-error@-1 {{expected identifier in module selector}} + // expected-error@-2 {{cannot find operator '.*' in scope}} + + _ = 1._::magnitude + // expected-error@-1 {{expected identifier in module selector}} + + _ = 1.Self::magnitude + // expected-error@-1 {{expected identifier in module selector}} + + _ = 1.self::magnitude + // expected-error@-1 {{expected identifier in module selector}} + + _ = 1.inout::magnitude + // expected-error@-1 {{expected identifier in module selector}} + + _ = 1.Any::magnitude + // expected-error@-1 {{expected identifier in module selector}} + } +} + +@_spi(main::Private) +// expected-error@-1 {{SPI group cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{7-13=}} +public struct BadImplementsAttr: CustomStringConvertible { + @_implements(CustomStringConvertible, Swift::description) + // expected-error@-1 {{name of sibling declaration cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{41-48=}} + public var stringValue: String { fatalError() } + + @_specialize(spi: main::Private, where T == Swift::Int) + // expected-error@-1 {{SPI group cannot be qualified with a module selector}} expected-note@-1 {{remove module selector from this name}} {{21-27=}} + public func fn() -> T { fatalError() } +} diff --git a/test/Parse/operator_decl.swift b/test/Parse/operator_decl.swift index 1daec13369d74..84e86053ef9d8 100644 --- a/test/Parse/operator_decl.swift +++ b/test/Parse/operator_decl.swift @@ -83,6 +83,9 @@ precedencegroup D { precedencegroup E { higherThan: } // expected-error {{expected name of related precedence group after 'higherThan'}} +precedencegroup EE { + higherThan: E, +} // expected-error {{expected name of related precedence group after 'higherThan'}} precedencegroup F { higherThan: A, B, C diff --git a/test/expr/postfix/dot/numeric_literals.swift b/test/expr/postfix/dot/numeric_literals.swift new file mode 100644 index 0000000000000..3675928a86497 --- /dev/null +++ b/test/expr/postfix/dot/numeric_literals.swift @@ -0,0 +1,9 @@ +// RUN: %target-typecheck-verify-swift + +func fn() { + _ = 1.description + _ = 1.5.description + + print(1.description) + print(1.5.description) +}