diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 931d751a03459..a89442f485d85 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -2133,7 +2133,10 @@ function(add_swift_target_library name) list(APPEND swiftlib_swift_compile_flags_all "-Fsystem" "${ios_support_frameworks_path}") list(APPEND swiftlib_c_compile_flags_all "-iframework" "${ios_support_frameworks_path}") - list(APPEND swiftlib_link_flags_all "-F" "${ios_support_frameworks_path}") + # We collate -F with the framework path to avoid unwanted deduplication + # of options by target_compile_options -- this way no undesired + # side effects are introduced should a new search path be added. + list(APPEND swiftlib_link_flags_all "-F${ios_support_frameworks_path}") endif() if(sdk IN_LIST SWIFT_APPLE_PLATFORMS AND SWIFTLIB_IS_SDK_OVERLAY) diff --git a/docs/SIL.rst b/docs/SIL.rst index 4358e2ec12f3a..256b14beb74f0 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -3495,46 +3495,8 @@ partial_apply // %r will be of the substituted thick function type $(Z'...) -> R' Creates a closure by partially applying the function ``%0`` to a partial -sequence of its arguments. In the instruction syntax, the type of the callee is -specified after the argument list; the types of the argument and of the defined -value are derived from the function type of the callee. If the ``partial_apply`` -has an escaping function type (not ``[on_stack]``) the closure context will be -allocated with retain count 1 and initialized to contain the values ``%1``, -``%2``, etc. The closed-over values will not be retained; that must be done -separately before the ``partial_apply``. The closure does however take ownership -of the partially applied arguments (except for ``@inout_aliasable`` parameters); -when the closure reference count reaches zero, the contained values will be -destroyed. If the ``partial_apply`` has a ``@noescape`` function type -(``partial_apply [on_stack]``) the closure context is allocated on the stack and -initialized to contain the closed-over values. The closed-over values are not -retained, lifetime of the closed-over values must be managed separately. The -lifetime of the stack context of a ``partial_apply [on_stack]`` must be -terminated with a ``dealloc_stack``. - -If the callee is generic, all of its generic parameters must be bound by the -given substitution list. The arguments are given with these generic -substitutions applied, and the resulting closure is of concrete function -type with the given substitutions applied. The generic parameters themselves -cannot be partially applied; all of them must be bound. The result is always -a concrete function. - -If an address argument has ``@inout_aliasable`` convention, the closure -obtained from ``partial_apply`` will not own its underlying value. -The ``@inout_aliasable`` parameter convention is used when a ``@noescape`` -closure captures an ``inout`` argument. - -TODO: The instruction, when applied to a generic function, -currently implicitly performs abstraction difference transformations enabled -by the given substitutions, such as promoting address-only arguments and returns -to register arguments. This should be fixed. - -By default, ``partial_apply`` creates a closure whose invocation takes ownership -of the context, meaning that a call implicitly releases the closure. The -``[callee_guaranteed]`` change this to a caller-guaranteed model, where the -caller promises not to release the closure while the function is being called. - -This instruction is used to implement both curry thunks and closures. A -curried function in Swift:: +sequence of its arguments. This instruction is used to implement both curry +thunks and closures. A curried function in Swift:: func foo(_ a:A)(b:B)(c:C)(d:D) -> E { /* body of foo */ } @@ -3607,6 +3569,54 @@ lowers to an uncurried entry point and is curried in the enclosing function:: return %ret : $Int } +**Ownership Semantics of Closure Context during Invocation**: By default, an +escaping ``partial_apply`` (``partial_apply`` without ``[on_stack]]`` creates a +closure whose invocation takes ownership of the context, meaning that a call +implicitly releases the closure. If the ``partial_apply`` is marked with the +flag ``[callee_guaranteed]`` the invocation instead uses a caller-guaranteed +model, where the caller promises not to release the closure while the function +is being called. + +**Captured Value Ownership Semantics**: In the instruction syntax, the type of +the callee is specified after the argument list; the types of the argument and +of the defined value are derived from the function type of the callee. Even so, +the ownership requirements of the partial apply are not the same as that of the +callee function (and thus said signature). Instead: + +1. If the ``partial_apply`` has a ``@noescape`` function type (``partial_apply + [on_stack]``) the closure context is allocated on the stack and is + initialized to contain the closed-over values without taking ownership of + those values. The closed-over values are not retained and the lifetime of the + closed-over values must be managed by other instruction independently of the + ``partial_apply``. The lifetime of the stack context of a ``partial_apply + [on_stack]`` must be terminated with a ``dealloc_stack``. + +2. If the ``partial_apply`` has an escaping function type (not ``[on_stack]``) + then the closure context will be heap allocated with a retain count of 1. Any + closed over parameters (except for ``@inout`` parameters) will be consumed by + the partial_apply. This ensures that no matter when the ``partial_apply`` is + called, the captured arguments are alive. When the closure context's + reference count reaches zero, the contained values are destroyed. If the + callee requires an owned parameter, then the implicit partial_apply forwarder + created by IRGen will copy the underlying argument and pass it to the callee. + +3. If an address argument has ``@inout_aliasable`` convention, the closure + obtained from ``partial_apply`` will not own its underlying value. The + ``@inout_aliasable`` parameter convention is used when a ``@noescape`` + closure captures an ``inout`` argument. + +**NOTE:** If the callee is generic, all of its generic parameters must be bound +by the given substitution list. The arguments are given with these generic +substitutions applied, and the resulting closure is of concrete function type +with the given substitutions applied. The generic parameters themselves cannot +be partially applied; all of them must be bound. The result is always a concrete +function. + +**TODO:** The instruction, when applied to a generic function, currently +implicitly performs abstraction difference transformations enabled by the given +substitutions, such as promoting address-only arguments and returns to register +arguments. This should be fixed. + builtin ``````` :: diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 789de8f2df163..b2727cd5572fb 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -335,7 +335,7 @@ class alignas(1 << DeclAlignInBits) Decl { IsStatic : 1 ); - SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+1+1+1+1+1+1+1, /// Encodes whether this is a 'let' binding. Introducer : 1, @@ -358,7 +358,10 @@ class alignas(1 << DeclAlignInBits) Decl { IsLazyStorageProperty : 1, /// Whether this is the backing storage for a property wrapper. - IsPropertyWrapperBackingProperty : 1 + IsPropertyWrapperBackingProperty : 1, + + /// Whether this is a lazily top-level global variable from the main file. + IsTopLevelGlobal : 1 ); SWIFT_INLINE_BITFIELD(ParamDecl, VarDecl, 1+2+NumDefaultArgumentKindBits, @@ -5084,6 +5087,10 @@ class VarDecl : public AbstractStorageDecl { Bits.VarDecl.IsLazyStorageProperty = IsLazyStorage; } + /// True if this is a top-level global variable from the main source file. + bool isTopLevelGlobal() const { return Bits.VarDecl.IsTopLevelGlobal; } + void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; } + /// Retrieve the custom attributes that attach property wrappers to this /// property. The returned list contains all of the attached property wrapper attributes in source order, /// which means the outermost wrapper attribute is provided first. diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index fef7af3b04473..3d46cd38c1d43 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -338,6 +338,10 @@ ERROR(cannot_convert_initializer_value,none, "cannot convert value of type %0 to specified type %1", (Type,Type)) ERROR(cannot_convert_initializer_value_protocol,none, "value of type %0 does not conform to specified type %1", (Type,Type)) +ERROR(cannot_convert_initializer_value_anyobject,none, + "value of type %0 expected to be instance of class or " + "class-constrained type", + (Type, Type)) ERROR(cannot_convert_initializer_value_nil,none, "'nil' cannot initialize specified type %0", (Type)) @@ -346,6 +350,10 @@ ERROR(cannot_convert_to_return_type,none, (Type,Type)) ERROR(cannot_convert_to_return_type_protocol,none, "return expression of type %0 does not conform to %1", (Type,Type)) +ERROR(cannot_convert_return_type_to_anyobject,none, + "return expression of type %0 expected to be an instance of " + "a class or class-constrained type", + (Type, Type)) ERROR(cannot_convert_to_return_type_nil,none, "'nil' is incompatible with return type %0", (Type)) @@ -440,7 +448,10 @@ NOTE(candidate_performs_illegal_ephemeral_conv,none, ERROR(cannot_convert_argument_value_protocol,none, "argument type %0 does not conform to expected type %1", (Type, Type)) - +ERROR(cannot_convert_argument_value_anyobject,none, + "argument type %0 expected to be an instance of " + "a class or class-constrained type", + (Type, Type)) ERROR(cannot_convert_argument_value_nil,none, "'nil' is not compatible with expected argument type %0", (Type)) @@ -536,6 +547,10 @@ NOTE(assign_protocol_conformance_fix_it,none, ERROR(cannot_convert_assign_protocol,none, "value of type %0 does not conform to %1 in assignment", (Type, Type)) +ERROR(cannot_convert_assign_anyobject,none, + "value of type %0 expected to be an instance of " + "a class or class-constrained type in assignment", + (Type, Type)) ERROR(cannot_convert_assign_nil,none, "'nil' cannot be assigned to type %0", (Type)) @@ -1138,14 +1153,12 @@ NOTE(candidate_expected_different_labels,none, "incorrect labels for candidate (have: '%0', expected: '%1')", (StringRef, StringRef)) +ERROR(member_shadows_function,none, + "use of %0 refers to %1 rather than %2 %3", + (DeclNameRef, DescriptiveDeclKind, DescriptiveDeclKind, DeclName)) ERROR(member_shadows_global_function,none, - "use of %0 refers to %1 %2 rather than %3 %4 in %5 %6", - (DeclNameRef, DescriptiveDeclKind, DeclName, DescriptiveDeclKind, - DeclName, DescriptiveDeclKind, DeclName)) -ERROR(member_shadows_global_function_near_match,none, - "use of %0 nearly matches %3 %4 in %5 %6 rather than %1 %2", - (DeclNameRef, DescriptiveDeclKind, DeclName, DescriptiveDeclKind, - DeclName, DescriptiveDeclKind, DeclName)) + "use of %0 refers to %1 rather than %2 %3 in module %4", + (DeclNameRef, DescriptiveDeclKind, DescriptiveDeclKind, DeclName, DeclName)) ERROR(instance_member_use_on_type,none, "instance member %1 cannot be used on type %0; " diff --git a/include/swift/AST/FineGrainedDependencies.h b/include/swift/AST/FineGrainedDependencies.h index 50cba234d0e46..49f0b755f9e39 100644 --- a/include/swift/AST/FineGrainedDependencies.h +++ b/include/swift/AST/FineGrainedDependencies.h @@ -799,6 +799,7 @@ class SourceFileDepGraph { compoundNamesByRDK); static constexpr char noncascadingOrPrivatePrefix = '#'; + static constexpr char nameFingerprintSeparator = ','; static std::string noncascading(std::string name); diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index ae4e11c5f563d..c125f046281c9 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -304,7 +304,7 @@ namespace swift { /// the interface hash, hash them into per-iterable-decl-context /// fingerprints. Fine-grained dependency types won't dirty every provides /// in a file when the user adds a member to, e.g., a struct. - bool EnableTypeFingerprints = false; + bool EnableTypeFingerprints = true; /// When using fine-grained dependencies, emit dot files for every swiftdeps /// file. diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index ed4f5dc34126e..7cf754731c1ab 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -243,6 +243,9 @@ class SourceManager { llvm::Optional resolveOffsetForEndOfLine(unsigned BufferId, unsigned Line) const; + /// Get the length of the line + llvm::Optional getLineLength(unsigned BufferId, unsigned Line) const; + SourceLoc getLocForLineCol(unsigned BufferId, unsigned Line, unsigned Col) const { auto Offset = resolveFromLineCol(BufferId, Line, Col); return Offset.hasValue() ? getLocForOffset(BufferId, Offset.getValue()) : diff --git a/include/swift/Driver/FineGrainedDependencyDriverGraph.h b/include/swift/Driver/FineGrainedDependencyDriverGraph.h index af7b2f5116c06..9d1e9954d2c15 100644 --- a/include/swift/Driver/FineGrainedDependencyDriverGraph.h +++ b/include/swift/Driver/FineGrainedDependencyDriverGraph.h @@ -437,7 +437,7 @@ class ModuleDepGraph { /// Call \p fn for each node whose key matches \p key. void forEachMatchingNode(const DependencyKey &key, - function_ref) const; + function_ref) const; void forEachNodeInJob(StringRef swiftDeps, function_ref) const; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index dd2d0c0d026f4..dbadf83aa6318 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -191,7 +191,7 @@ HelpText<"Emit dot files every time driver imports an fine-grained swiftdeps fil def fine_grained_dependency_include_intrafile : Flag<["-"], "fine-grained-dependency-include-intrafile">, -InternalDebugOpt, +Flags<[FrontendOption, HelpHidden]>, HelpText<"Include within-file dependencies.">; def emit_fine_grained_dependency_sourcefile_dot_files : diff --git a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h index c1d405c4d7f42..2d56b97d85695 100644 --- a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h @@ -449,7 +449,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Sets the outgoing points-to edge. The \p To node must be a Content node. void setPointsToEdge(CGNode *To) { - assert(!To->mergeTo); + assert(!To->isMerged); assert(To->Type == NodeType::Content && "Wrong node type for points-to edge"); pointsToIsEdge = true; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ef6969430da40..a5d494d2805df 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2431,7 +2431,8 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD, if (isInitializingCtor) { // initializing constructors of value types always have an implicitly // inout self. - selfAccess = SelfAccessKind::Mutating; + if (!containerTy->hasReferenceSemantics()) + selfAccess = SelfAccessKind::Mutating; } else { // allocating constructors have metatype 'self'. isStatic = true; @@ -2459,10 +2460,6 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD, if (isStatic) return AnyFunctionType::Param(MetatypeType::get(selfTy, Ctx)); - // Reference types have 'self' of type T. - if (containerTy->hasReferenceSemantics()) - return AnyFunctionType::Param(selfTy); - auto flags = ParameterTypeFlags(); switch (selfAccess) { case SelfAccessKind::Consuming: diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index ae20364d0bb82..dd93348812558 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3762,6 +3762,10 @@ void Type::dump() const { } void Type::dump(raw_ostream &os, unsigned indent) const { + #if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB + return; // not needed for the parser library. + #endif + PrintType(os, indent).visit(*this, ""); os << "\n"; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 25f90c3d45002..8bdb94abff1c9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5312,6 +5312,7 @@ VarDecl::VarDecl(DeclKind kind, bool isStatic, VarDecl::Introducer introducer, Bits.VarDecl.IsLazyStorageProperty = false; Bits.VarDecl.HasNonPatternBindingInit = false; Bits.VarDecl.IsPropertyWrapperBackingProperty = false; + Bits.VarDecl.IsTopLevelGlobal = false; } Type VarDecl::getType() const { @@ -5410,11 +5411,7 @@ bool VarDecl::isLazilyInitializedGlobal() const { // Top-level global variables in the main source file and in the REPL are not // lazily initialized. - auto sourceFileContext = dyn_cast(getDeclContext()); - if (!sourceFileContext) - return true; - - return !sourceFileContext->isScriptMode(); + return !isTopLevelGlobal(); } SourceRange VarDecl::getSourceRange() const { diff --git a/lib/AST/FineGrainedDependenciesSourceFileDepGraphConstructor.cpp b/lib/AST/FineGrainedDependenciesSourceFileDepGraphConstructor.cpp index 41df94b5fab71..eba5fe33192bb 100644 --- a/lib/AST/FineGrainedDependenciesSourceFileDepGraphConstructor.cpp +++ b/lib/AST/FineGrainedDependenciesSourceFileDepGraphConstructor.cpp @@ -680,12 +680,10 @@ class SourceFileDepGraphConstructor { for (const auto &contextNameFingerprint : contextNameFingerprints) { auto p = g.findExistingNodePairOrCreateAndAddIfNew( kind, contextNameFingerprint); - // When we don't have a fingerprint yet, must rebuild every provider when - // interfaceHash changes. So when interface (i.e. interface hash) of - // sourceFile changes, every provides is dirty. And since we don't know - // what happened, dirtyness might affect the interface. - if (!p.getInterface()->getFingerprint().hasValue()) - g.addArc(g.getSourceFileNodePair().getInterface(), p.getInterface()); + // Since the current type fingerprints only include tokens in the body, + // when the interface hash changes, it is possible that the type in the + // file has changed. + g.addArc(g.getSourceFileNodePair().getInterface(), p.getInterface()); } } @@ -809,8 +807,15 @@ bool swift::fine_grained_dependencies::emitReferenceDependencies( // that may have been there. No error handling -- this is just a nicety, it // doesn't matter if it fails. llvm::sys::fs::rename(outputPath, outputPath + "~"); + // Since, when fingerprints are enabled, + // the parser diverts token hashing into per-body fingerprints + // before it can know if a difference is in a private type, + // in order to be able to test the changed fingerprints + // we force the inclusion of private declarations when fingerprints + // are enabled. const bool includeIntrafileDeps = - SF->getASTContext().LangOpts.FineGrainedDependenciesIncludeIntrafileOnes; + SF->getASTContext().LangOpts.FineGrainedDependenciesIncludeIntrafileOnes || + SF->getASTContext().LangOpts.EnableTypeFingerprints; const bool hadCompilationError = SF->getASTContext().hadError(); auto gc = SourceFileDepGraphConstructor::forSourceFile( SF, depTracker, outputPath, includeIntrafileDeps, hadCompilationError); @@ -843,12 +848,29 @@ bool swift::fine_grained_dependencies::emitReferenceDependencies( static StringRef stripPrefix(const StringRef name) { return name.ltrim(SourceFileDepGraph::noncascadingOrPrivatePrefix); } +static StringRef stripFingerprint(const StringRef nameAndFingerprint) { + return nameAndFingerprint.split(SourceFileDepGraph::nameFingerprintSeparator) + .first; +} +static StringRef stripName(const StringRef nameAndFingerprint) { + return nameAndFingerprint.split(SourceFileDepGraph::nameFingerprintSeparator) + .second; +} +static std::string extractName(const StringRef prefixNameFingerprint) { + return stripFingerprint(stripPrefix(prefixNameFingerprint)).str(); +} +static Optional extractFingerprint( + const StringRef prefixNameFingerprint) { + const auto fp = stripName(stripPrefix(prefixNameFingerprint)); + return fp.empty() ? None : Optional(fp.str()); +} static std::vector getBaseNameProvides(ArrayRef simpleNames) { std::vector result; for (StringRef n : simpleNames) - result.push_back(ContextNameFingerprint("", stripPrefix(n).str(), None)); + result.push_back(ContextNameFingerprint("", extractName(n), + extractFingerprint(n))); return result; } @@ -856,7 +878,8 @@ static std::vector getMangledHolderProvides(ArrayRef simpleNames) { std::vector result; for (StringRef n : simpleNames) - result.push_back(ContextNameFingerprint(stripPrefix(n).str(), "", None)); + result.push_back(ContextNameFingerprint(extractName(n), "", + extractFingerprint(n))); return result; } @@ -864,12 +887,15 @@ static std::vector getCompoundProvides( ArrayRef> compoundNames) { std::vector result; for (const auto &p : compoundNames) - result.push_back(ContextNameFingerprint(stripPrefix(p.first), - stripPrefix(p.second), None)); + result.push_back(ContextNameFingerprint(extractName(p.first), + extractName(p.second), + extractFingerprint(p.second))); return result; } -static bool cascades(const std::string &s) { return s.empty() || s[0] != SourceFileDepGraph::noncascadingOrPrivatePrefix; } +static bool cascades(const std::string &s) { + return s.empty() || s[0] != SourceFileDepGraph::noncascadingOrPrivatePrefix; +} // Use '_' as a prefix for a file-private member static bool isPrivate(const std::string &s) { @@ -899,7 +925,8 @@ getCompoundDepends( // (On Linux, the compiler needs more verbosity than: // result.push_back({{n, "", false}, cascades(n)}); result.push_back( - std::make_pair(std::make_tuple(stripPrefix(n), std::string(), false), cascades(n))); + std::make_pair(std::make_tuple(stripPrefix(n), std::string(), false), + cascades(n))); } for (auto &p : compoundNames) { // Likewise, for Linux expand the following out: @@ -927,7 +954,8 @@ SourceFileDepGraph SourceFileDepGraph::simulateLoad( SourceFileDepGraphConstructor c( swiftDepsFilename, includePrivateDeps, hadCompilationError, interfaceHash, getSimpleDepends(simpleNamesByRDK[dependsTopLevel]), - getCompoundDepends(simpleNamesByRDK[dependsNominal], compoundNamesByRDK[dependsMember]), + getCompoundDepends(simpleNamesByRDK[dependsNominal], + compoundNamesByRDK[dependsMember]), getSimpleDepends(simpleNamesByRDK[dependsDynamicLookup]), getExternalDepends(simpleNamesByRDK[dependsExternal]), {}, // precedence groups diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index fd60da8ff5379..6cd7577ce3f93 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -11,32 +11,59 @@ else() set(UUID_INCLUDE "${UUID_INCLUDE_DIRS}") endif() -function(generate_revision_inc revision_inc_var name dir) - find_first_existing_vc_file("${dir}" ${name}_vc) +# Figure out if we can track VC revisions. +# FIXME: Copied from Clang. +function(find_first_existing_file out_var) + foreach(file ${ARGN}) + if(EXISTS "${file}") + set(${out_var} "${file}" PARENT_SCOPE) + return() + endif() + endforeach() +endfunction() - # Create custom target to generate the VC revision include. - set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/${name}Revision.inc") +macro(find_first_existing_vc_file out_var path) + find_first_existing_file(${out_var} + "${path}/.git/logs/HEAD" # Git + "${path}/.svn/wc.db" # SVN 1.7 + "${path}/.svn/entries" # SVN 1.6 + ) +endmacro() - set(generate_vcs_version_script "${LLVM_MAIN_SRC_DIR}/cmake/modules/GenerateVersionFromVCS.cmake") +set(generate_vcs_version_script "${LLVM_MAIN_SRC_DIR}/cmake/modules/GenerateVersionFromVCS.cmake") - add_custom_command(OUTPUT "${version_inc}" - DEPENDS "${${name}_vc}" "${generate_vcs_version_script}" - COMMAND ${CMAKE_COMMAND} "-DNAMES=$" - "-D$_SOURCE_DIR=${dir}" - "-DHEADER_FILE=${version_inc}" - -P "${generate_vcs_version_script}") +function(generate_revision_inc revision_inc_var name dir) + find_first_existing_vc_file(dep_file "${dir}") + # Create custom target to generate the VC revision include. + set(revision_inc "${CMAKE_CURRENT_BINARY_DIR}/${name}Revision.inc") + string(TOUPPER ${name} upper_name) + if(DEFINED dep_file) + add_custom_command(OUTPUT "${revision_inc}" + DEPENDS "${dep_file}" "${generate_vcs_version_script}" + COMMAND + ${CMAKE_COMMAND} "-DNAMES=${upper_name}" + "-D${upper_name}_SOURCE_DIR=${dir}" + "-DHEADER_FILE=${revision_inc}" + -P "${generate_vcs_version_script}") + else() + # Generate an empty Revision.inc file if we are not using git or SVN. + file(WRITE "${revision_inc}" "") + endif() # Mark the generated header as being generated. - set_source_files_properties("${version_inc}" + set_source_files_properties("${revision_inc}" PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE) - set(${revision_inc_var} ${version_inc} PARENT_SCOPE) + set(${revision_inc_var} ${revision_inc} PARENT_SCOPE) endfunction() generate_revision_inc(llvm_revision_inc LLVM "${LLVM_MAIN_SRC_DIR}") generate_revision_inc(clang_revision_inc Clang "${CLANG_MAIN_SRC_DIR}") generate_revision_inc(swift_revision_inc Swift "${SWIFT_SOURCE_DIR}") +set(version_inc_files + ${llvm_revision_inc} ${clang_revision_inc} ${swift_revision_inc}) + add_swift_host_library(swiftBasic STATIC AnyValue.cpp Cache.cpp @@ -68,10 +95,7 @@ add_swift_host_library(swiftBasic STATIC Unicode.cpp UUID.cpp Version.cpp - - ${llvm_revision_inc} - ${clang_revision_inc} - ${swift_revision_inc} + ${version_inc_files} # Platform-specific TaskQueue implementations Unix/TaskQueue.inc diff --git a/lib/Basic/SourceLoc.cpp b/lib/Basic/SourceLoc.cpp index 7c66731e41fe1..76547ff2e91f6 100644 --- a/lib/Basic/SourceLoc.cpp +++ b/lib/Basic/SourceLoc.cpp @@ -331,10 +331,20 @@ SourceManager::resolveOffsetForEndOfLine(unsigned BufferId, return resolveFromLineCol(BufferId, Line, ~0u); } +llvm::Optional +SourceManager::getLineLength(unsigned BufferId, unsigned Line) const { + auto BegOffset = resolveFromLineCol(BufferId, Line, 0); + auto EndOffset = resolveFromLineCol(BufferId, Line, ~0u); + if (BegOffset && EndOffset) { + return EndOffset.getValue() - BegOffset.getValue(); + } + return None; +} + llvm::Optional SourceManager::resolveFromLineCol(unsigned BufferId, unsigned Line, unsigned Col) const { - if (Line == 0 || Col == 0) { + if (Line == 0) { return None; } const bool LineEnd = Col == ~0u; @@ -353,6 +363,9 @@ llvm::Optional SourceManager::resolveFromLineCol(unsigned BufferId, return None; } Ptr = LineStart; + if (Col == 0) { + return Ptr - InputBuf->getBufferStart(); + } // The <= here is to allow for non-inclusive range end positions at EOF for (; ; ++Ptr) { --Col; diff --git a/lib/Driver/FineGrainedDependencyDriverGraph.cpp b/lib/Driver/FineGrainedDependencyDriverGraph.cpp index dd997a283f1ca..5bda1956f9b4c 100644 --- a/lib/Driver/FineGrainedDependencyDriverGraph.cpp +++ b/lib/Driver/FineGrainedDependencyDriverGraph.cpp @@ -171,6 +171,11 @@ ModuleDepGraph::findJobsToRecompileWhenNodesChange< std::unordered_set>( const std::unordered_set &); +template std::vector +ModuleDepGraph::findJobsToRecompileWhenNodesChange< + std::vector>( + const std::vector &); + std::vector ModuleDepGraph::computeSwiftDepsFromNodes( ArrayRef nodes) const { llvm::StringSet<> swiftDepsOfNodes; @@ -441,7 +446,7 @@ void ModuleDepGraph::forEachNode( void ModuleDepGraph::forEachMatchingNode( const DependencyKey &key, - function_ref fn) const { + function_ref fn) const { nodeMap.forEachValueMatching( key, [&](const std::string &, ModuleDepGraphNode *n) { fn(n); }); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 15b3c1b33d293..6edbf335b8d78 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5840,6 +5840,7 @@ Parser::parseDeclVar(ParseDeclOptions Flags, VD->setStatic(StaticLoc.isValid()); VD->getAttrs() = Attributes; setLocalDiscriminator(VD); + VD->setTopLevelGlobal(topLevelDecl); // Set original declaration in `@differentiable` attributes. setOriginalDeclarationForDifferentiableAttributes(Attributes, VD); diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index 6e0fac061678f..8b667f595bdb2 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -983,10 +983,8 @@ class DestructureInputs { for (auto i : indices(substTupleTy.getElementTypes())) { auto &elt = substTupleTy->getElement(i); auto ownership = elt.getParameterFlags().getValueOwnership(); - // FIXME(swift3): Once the entire parameter list is no longer a - // target for substitution, re-enable this. - // assert(ownership == ValueOwnership::Default); - // assert(!elt.isVararg()); + assert(ownership == ValueOwnership::Default); + assert(!elt.isVararg()); visit(ownership, forSelf, origType.getTupleElementType(i), CanType(elt.getRawType()), rep); diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 4900797283f88..976b9c790185c 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -64,6 +64,10 @@ llvm::cl::opt SILPrintDebugInfo("sil-print-debuginfo", llvm::cl::init(false), llvm::cl::desc("Include debug info in SIL output")); +llvm::cl::opt +SILPrintSourceInfo("sil-print-sourceinfo", llvm::cl::init(false), + llvm::cl::desc("Include source annotation in SIL output")); + llvm::cl::opt SILPrintGenericSpecializationInfo( "sil-print-generic-specialization-info", llvm::cl::init(false), llvm::cl::desc("Include generic specialization" @@ -618,7 +622,22 @@ class SILPrinter : public SILInstructionVisitor { } *this << '\n'; + const auto &SM = BB->getModule().getASTContext().SourceMgr; + Optional PrevLoc; for (const SILInstruction &I : *BB) { + if (SILPrintSourceInfo) { + auto CurSourceLoc = I.getLoc().getSourceLoc(); + if (CurSourceLoc.isValid()) { + if (!PrevLoc || SM.getLineNumber(CurSourceLoc) > SM.getLineNumber(PrevLoc->getSourceLoc())) { + auto Buffer = SM.findBufferContainingLoc(CurSourceLoc); + auto Line = SM.getLineNumber(CurSourceLoc); + auto LineLength = SM.getLineLength(Buffer, Line); + PrintState.OS << " // " << SM.extractText({SM.getLocForLineCol(Buffer, Line, 0), LineLength.getValueOr(0)}) << + "\tSourceLoc: " << SM.getDisplayNameForLoc(CurSourceLoc) << ":" << Line << "\n"; + PrevLoc = I.getLoc(); + } + } + } Ctx.printInstructionCallBack(&I); if (SILPrintGenericSpecializationInfo) { if (auto AI = ApplySite::isa(const_cast(&I))) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 74f9b04070f75..879c9082c6272 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -5023,13 +5023,17 @@ RValue RValueEmitter::visitMakeTemporarilyEscapableExpr( return visit(E->getSubExpr(), C); }; - // Handle @convention(block). No withoutActuallyEscaping verification yet. - if (silFnTy->getExtInfo().getRepresentation() != - SILFunctionTypeRepresentation::Thick) { + // Handle @convention(block) an @convention(c). No withoutActuallyEscaping + // verification yet. + auto closureRepresentation = silFnTy->getExtInfo().getRepresentation(); + if (closureRepresentation != SILFunctionTypeRepresentation::Thick) { auto escapingClosure = SGF.B.createConvertFunction(E, functionValue, escapingFnTy, /*WithoutActuallyEscaping=*/true); - return visitSubExpr(escapingClosure, true /*isClosureConsumable*/); + bool isBlockConvention = + closureRepresentation == SILFunctionTypeRepresentation::Block; + return visitSubExpr(escapingClosure, + isBlockConvention /*isClosureConsumable*/); } // Convert it to an escaping function value. diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 62e0059646990..e5b1eec09a578 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -122,6 +122,7 @@ SILValue EscapeAnalysis::getPointerBase(SILValue value) { case ValueKind::StructElementAddrInst: case ValueKind::StructExtractInst: case ValueKind::TupleElementAddrInst: + case ValueKind::BeginAccessInst: case ValueKind::UncheckedTakeEnumDataAddrInst: case ValueKind::UncheckedEnumDataInst: case ValueKind::MarkDependenceInst: diff --git a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp index c48c161cb28ed..b4265a2690aa3 100644 --- a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp +++ b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp @@ -849,11 +849,16 @@ bool COWArrayOpt::hoistMakeMutable(ArraySemanticsCall MakeMutable, // Check whether we can hoist make_mutable based on the operations that are // in the loop. - // Note that in this case we don't verify that the array buffer is not aliased - // and therefore we must be conservative if the make_mutable is executed - // conditionally (i.e. doesn't dominate all exit blocks). - // The test SILOptimizer/cowarray_opt.sil: dont_hoist_if_executed_conditionally - // shows the problem. + // + // Hoisting make_mutable releases the original array storage. If an alias of + // that storage is accessed on any path reachable from the loop header that + // doesn't already pass through the make_mutable, then hoisting is + // illegal. hasLoopOnlyDestructorSafeArrayOperations checks that the array + // storage is not accessed within the loop. However, this does not include + // paths exiting the loop. Rather than analyzing code outside the loop, simply + // check that the original make_mutable dominates all exits. The test + // SILOptimizer/cowarray_opt.sil: dont_hoist_if_executed_conditionally shows + // the problem. if (hasLoopOnlyDestructorSafeArrayOperations() && dominatesExits) { // Done. We can hoist the make_mutable. // We still need the array uses later to check if we can add loads to diff --git a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp index 6923725dc55b6..107829132d2a8 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp @@ -185,12 +185,9 @@ static void propagateBasicBlockArgs(SILBasicBlock &BB) { // this to CCP and trigger another round of copy propagation. SILArgument *Arg = *AI; - // If this argument is guaranteed and Args[Idx] is a SILFunctionArgument, - // delete the end_borrow. - if (Arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed && - isa(Args[Idx])) { + // If this argument is guaranteed and Args[Idx], delete the end_borrow. + if (Arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed) deleteEndBorrows(Arg); - } // We were able to fold, so all users should use the new folded value. Arg->replaceAllUsesWith(Args[Idx]); diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index d2f21354ab52e..0dff01b97cc29 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1107,8 +1107,14 @@ Optional TypeChecker::applyFunctionBuilderBodyTransform( } // Apply the solution to the function body. - return cast_or_null( - cs.applySolutionToBody(solutions.front(), func)); + if (auto result = cs.applySolution( + solutions.front(), + SolutionApplicationTarget(func), + /*performingDiagnostics=*/false)) { + return result->getFunctionBody(); + } + + return nullptr; } ConstraintSystem::TypeMatchResult ConstraintSystem::matchFunctionBuilder( diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 770b79c72a9c2..443f67d35fd29 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7231,14 +7231,14 @@ bool ConstraintSystem::applySolutionFixes(const Solution &solution) { /// Apply a given solution to the expression, producing a fully /// type-checked expression. -llvm::PointerUnion ConstraintSystem::applySolutionImpl( - Solution &solution, SolutionApplicationTarget target, Type convertType, - bool discardedExpr, bool performingDiagnostics) { +Optional ConstraintSystem::applySolution( + Solution &solution, SolutionApplicationTarget target, + bool performingDiagnostics) { // If any fixes needed to be applied to arrive at this solution, resolve // them to specific expressions. if (!solution.Fixes.empty()) { if (shouldSuppressDiagnostics()) - return nullptr; + return None; bool diagnosedErrorsViaFixes = applySolutionFixes(solution); // If all of the available fixes would result in a warning, @@ -7248,12 +7248,12 @@ llvm::PointerUnion ConstraintSystem::applySolutionImpl( })) { // If we already diagnosed any errors via fixes, that's it. if (diagnosedErrorsViaFixes) - return nullptr; + return None; // If we didn't manage to diagnose anything well, so fall back to // diagnosing mining the system to construct a reasonable error message. diagnoseFailureFor(target); - return nullptr; + return None; } } @@ -7261,9 +7261,13 @@ llvm::PointerUnion ConstraintSystem::applySolutionImpl( ExprWalker walker(rewriter); // Apply the solution to the target. - llvm::PointerUnion result; + SolutionApplicationTarget result = target; if (auto expr = target.getAsExpr()) { - result = expr->walk(walker); + Expr *rewrittenExpr = expr->walk(walker); + if (!rewrittenExpr) + return None; + + result.setExpr(rewrittenExpr); } else { auto fn = *target.getAsFunction(); @@ -7284,14 +7288,11 @@ llvm::PointerUnion ConstraintSystem::applySolutionImpl( }); if (!newBody) - return result; + return None; - result = newBody; + result.setFunctionBody(newBody); } - if (result.isNull()) - return result; - // If we're re-typechecking an expression for diagnostics, don't // visit closures that have non-single expression bodies. if (!performingDiagnostics) { @@ -7309,15 +7310,17 @@ llvm::PointerUnion ConstraintSystem::applySolutionImpl( // If any of them failed to type check, bail. if (hadError) - return nullptr; + return None; } - if (auto resultExpr = result.dyn_cast()) { + if (auto resultExpr = result.getAsExpr()) { Expr *expr = target.getAsExpr(); assert(expr && "Can't have expression result without expression target"); + // We are supposed to use contextual type only if it is present and // this expression doesn't represent the implicit return of the single // expression function which got deduced to be `Never`. + Type convertType = target.getExprConversionType(); auto shouldCoerceToContextualType = [&]() { return convertType && !(getType(resultExpr)->isUninhabited() && @@ -7328,19 +7331,22 @@ llvm::PointerUnion ConstraintSystem::applySolutionImpl( // If we're supposed to convert the expression to some particular type, // do so now. if (shouldCoerceToContextualType()) { - result = rewriter.coerceToType(resultExpr, convertType, - getConstraintLocator(expr)); - if (!result) - return nullptr; - } else if (getType(resultExpr)->hasLValueType() && !discardedExpr) { + resultExpr = rewriter.coerceToType(resultExpr, + simplifyType(convertType), + getConstraintLocator(expr)); + } else if (getType(resultExpr)->hasLValueType() && + !target.isDiscardedExpr()) { // We referenced an lvalue. Load it. - result = rewriter.coerceToType(resultExpr, - getType(resultExpr)->getRValueType(), - getConstraintLocator(expr)); + resultExpr = rewriter.coerceToType(resultExpr, + getType(resultExpr)->getRValueType(), + getConstraintLocator(expr)); } - if (resultExpr) - solution.setExprTypes(resultExpr); + if (!resultExpr) + return None; + + solution.setExprTypes(resultExpr); + result.setExpr(resultExpr); } rewriter.finalize(); @@ -7509,16 +7515,21 @@ ArrayRef SolutionResult::getAmbiguousSolutions() const { MutableArrayRef SolutionResult::takeAmbiguousSolutions() && { assert(getKind() == Ambiguous); + markAsDiagnosed(); return MutableArrayRef(solutions, numSolutions); } -llvm::PointerUnion SolutionApplicationTarget::walk( - ASTWalker &walker) { +SolutionApplicationTarget SolutionApplicationTarget::walk(ASTWalker &walker) { switch (kind) { - case Kind::expression: - return getAsExpr()->walk(walker); + case Kind::expression: { + SolutionApplicationTarget result = *this; + result.setExpr(getAsExpr()->walk(walker)); + return result; + } case Kind::function: - return getAsFunction()->getBody()->walk(walker); + return SolutionApplicationTarget( + *getAsFunction(), + cast_or_null(getFunctionBody()->walk(walker))); } } diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 1910e242ce091..e8e865c13e43a 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -201,10 +201,6 @@ class FailureDiagnosis :public ASTVisitor{ ContextualTypePurpose CTP, Type suggestedType = Type()); - bool diagnoseImplicitSelfErrors(Expr *fnExpr, Expr *argExpr, - CalleeCandidateInfo &CCI, - ArrayRef argLabels); - private: /// Validate potential contextual type for type-checking one of the /// sub-expressions, usually correct/valid types are the ones which @@ -221,7 +217,6 @@ class FailureDiagnosis :public ASTVisitor{ validateContextualType(Type contextualType, ContextualTypePurpose CTP); bool visitExpr(Expr *E); - bool visitTryExpr(TryExpr *E); bool visitApplyExpr(ApplyExpr *AE); bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E); @@ -395,15 +390,10 @@ Expr *FailureDiagnosis::typeCheckChildIndependently( // type check operation. Expr *preCheckedExpr = subExpr; - // Disable structural checks, because we know that the overall expression - // has type constraint problems, and we don't want to know about any - // syntactic issues in a well-typed subexpression (which might be because - // the context is missing). - TypeCheckExprOptions TCEOptions = TypeCheckExprFlags::DisableStructuralChecks; - // Make sure that typechecker knows that this is an attempt // to diagnose a problem. - TCEOptions |= TypeCheckExprFlags::SubExpressionDiagnostics; + TypeCheckExprOptions TCEOptions = + TypeCheckExprFlags::SubExpressionDiagnostics; // Claim that the result is discarded to preserve the lvalue type of // the expression. @@ -964,223 +954,6 @@ decomposeArgType(Type argType, ArrayRef argLabels) { return result; } -bool FailureDiagnosis::diagnoseImplicitSelfErrors( - Expr *fnExpr, Expr *argExpr, CalleeCandidateInfo &CCI, - ArrayRef argLabels) { - // If candidate list is empty it means that problem is somewhere else, - // since we need to have candidates which might be shadowing other funcs. - if (CCI.empty() || !CCI[0].getDecl()) - return false; - - auto &ctx = CS.getASTContext(); - // Call expression is formed as 'foo.bar' where 'foo' might be an - // implicit "Self" reference, such use wouldn't provide good diagnostics - // for situations where instance members have equal names to functions in - // Swift Standard Library e.g. min/max. - auto UDE = dyn_cast(fnExpr); - if (!UDE) - return false; - - auto baseExpr = dyn_cast(UDE->getBase()); - if (!baseExpr) - return false; - - auto baseDecl = baseExpr->getDecl(); - if (!baseExpr->isImplicit() || baseDecl->getFullName() != ctx.Id_self) - return false; - - // Our base expression is an implicit 'self.' reference e.g. - // - // extension Sequence { - // func test() -> Int { - // return max(1, 2) - // } - // } - // - // In this example the Sequence class already has two methods named 'max' - // none of which accept two arguments, but there is a function in - // Swift Standard Library called 'max' which does accept two arguments, - // so user might have called that by mistake without realizing that - // compiler would add implicit 'self.' prefix to the call of 'max'. - auto argType = CS.getType(argExpr); - // If argument wasn't properly type-checked, let's retry without changing AST. - if (!argType || argType->hasUnresolvedType() || argType->hasTypeVariable() || - argType->hasTypeParameter()) { - auto *argTuple = dyn_cast(argExpr); - if (!argTuple) { - // Bail out if we don't have a well-formed argument list. - return false; - } - - // Let's type check individual argument expressions without any - // contextual information to try to recover an argument type that - // matches what the user actually wrote instead of what the typechecker - // expects. - SmallVector elts; - for (unsigned i = 0, e = argTuple->getNumElements(); i < e; ++i) { - ConcreteDeclRef ref = nullptr; - auto *el = argTuple->getElement(i); - auto typeResult = - TypeChecker::getTypeOfExpressionWithoutApplying(el, CS.DC, ref); - if (!typeResult) - return false; - auto flags = ParameterTypeFlags().withInOut(typeResult->is()); - elts.push_back(TupleTypeElt(typeResult->getInOutObjectType(), - argTuple->getElementName(i), - flags)); - } - - argType = TupleType::get(elts, CS.getASTContext()); - } - - auto typeKind = argType->getKind(); - if (typeKind != TypeKind::Tuple && typeKind != TypeKind::Paren) - return false; - - // If argument type couldn't be properly resolved or has errors, - // we can't diagnose anything in here, it points to the different problem. - if (isUnresolvedOrTypeVarType(argType) || argType->hasError()) - return false; - - auto context = CS.DC; - using CandidateMap = - llvm::SmallDenseMap>; - - auto getBaseKind = [](ValueDecl *base) -> DescriptiveDeclKind { - DescriptiveDeclKind kind = DescriptiveDeclKind::Module; - if (!base) - return kind; - - auto context = base->getDeclContext(); - do { - if (isa(context)) - return DescriptiveDeclKind::Extension; - - if (auto nominal = dyn_cast(context)) { - kind = nominal->getDescriptiveKind(); - break; - } - - context = context->getParent(); - } while (context); - - return kind; - }; - - auto diagnoseShadowing = [&](ValueDecl *base, - ArrayRef candidates) -> bool { - CalleeCandidateInfo calleeInfo(base ? base->getInterfaceType() : nullptr, - candidates, CCI.hasTrailingClosure, CS, - base); - - calleeInfo.filterListArgs(decomposeArgType(argType, argLabels)); - - auto diagnostic = diag::member_shadows_global_function_near_match; - switch (calleeInfo.closeness) { - case CC_Unavailable: - case CC_Inaccessible: - case CC_SelfMismatch: - case CC_ArgumentLabelMismatch: - case CC_ArgumentCountMismatch: - case CC_GeneralMismatch: - return false; - - case CC_NonLValueInOut: - case CC_OneArgumentNearMismatch: - case CC_OneArgumentMismatch: - case CC_OneGenericArgumentNearMismatch: - case CC_OneGenericArgumentMismatch: - case CC_ArgumentNearMismatch: - case CC_ArgumentMismatch: - case CC_GenericNonsubstitutableMismatch: - break; // Near match cases - - case CC_ExactMatch: - diagnostic = diag::member_shadows_global_function; - break; - } - - auto choice = calleeInfo.candidates[0].getDecl(); - auto baseKind = getBaseKind(base); - auto baseName = getBaseName(choice->getDeclContext()); - - auto origCandidate = CCI[0].getDecl(); - ctx.Diags.diagnose(UDE->getLoc(), diagnostic, UDE->getName(), - origCandidate->getDescriptiveKind(), - origCandidate->getFullName(), - choice->getDescriptiveKind(), - choice->getFullName(), baseKind, baseName); - - auto topLevelDiag = diag::fix_unqualified_access_top_level; - if (baseKind == DescriptiveDeclKind::Module) - topLevelDiag = diag::fix_unqualified_access_top_level_multi; - - emitFixItForExplicitlyQualifiedReference(ctx.Diags, UDE, topLevelDiag, - baseName, - choice->getDescriptiveKind()); - - for (auto &candidate : calleeInfo.candidates) { - if (auto decl = candidate.getDecl()) - ctx.Diags.diagnose(decl, diag::decl_declared_here, decl->getFullName()); - } - - return true; - }; - - // For each of the parent contexts, let's try to find any candidates - // which have the same name and the same number of arguments as callee. - while (context->getParent()) { - auto result = - TypeChecker::lookupUnqualified(context, UDE->getName(), UDE->getLoc()); - context = context->getParent(); - - if (!result || result.empty()) - continue; - - CandidateMap candidates; - for (const auto &candidate : result) { - auto base = candidate.getBaseDecl(); - auto decl = candidate.getValueDecl(); - if ((base && base->isInvalid()) || decl->isInvalid()) - continue; - - // If base is present but it doesn't represent a valid nominal, - // we can't use current candidate as one of the choices. - if (base && !base->getInterfaceType()->getNominalOrBoundGenericNominal()) - continue; - - auto context = decl->getDeclContext(); - // We are only interested in static or global functions, because - // there is no way to call anything else properly. - if (!decl->isStatic() && !context->isModuleScopeContext()) - continue; - - OverloadChoice choice(base ? base->getInterfaceType() : nullptr, - decl, UDE->getFunctionRefKind()); - - if (base) { // Let's group all of the candidates have a common base. - candidates[base].push_back(choice); - continue; - } - - // If there is no base, it means this is one of the global functions, - // let's try to diagnose its shadowing inline. - if (diagnoseShadowing(base, choice)) - return true; - } - - if (candidates.empty()) - continue; - - for (const auto &candidate : candidates) { - if (diagnoseShadowing(candidate.getFirst(), candidate.getSecond())) - return true; - } - } - - return false; -} - // Extract expression for failed argument number static Expr *getFailedArgumentExpr(CalleeCandidateInfo CCI, Expr *argExpr) { if (auto *TE = dyn_cast(argExpr)) @@ -1202,10 +975,6 @@ static Expr *getFailedArgumentExpr(CalleeCandidateInfo CCI, Expr *argExpr) { bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI, Expr *fnExpr, Expr *argExpr, ArrayRef argLabels) { - // Try to diagnose errors related to the use of implicit self reference. - if (diagnoseImplicitSelfErrors(fnExpr, argExpr, CCI, argLabels)) - return true; - // If we have a failure where the candidate set differs on exactly one // argument, and where we have a consistent mismatch across the candidate set // (often because there is only one candidate in the set), then diagnose this @@ -1425,12 +1194,6 @@ visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) { return false; } -/// A TryExpr doesn't change it's argument, nor does it change the contextual -/// type. -bool FailureDiagnosis::visitTryExpr(TryExpr *E) { - return visit(E->getSubExpr()); -} - bool FailureDiagnosis::visitExpr(Expr *E) { // Check each of our immediate children to see if any of them are // independently invalid. diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index b8cf4a95a75bb..0192c19079721 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -560,6 +560,7 @@ Optional> GenericArgumentsMismatchFailure::getDiagnosticFor( case CTP_ReturnSingleExpr: return diag::cannot_convert_to_return_type; case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: return diag::cannot_convert_default_arg_value; case CTP_YieldByValue: return diag::cannot_convert_yield_value; @@ -640,7 +641,7 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() { switch (last.getKind()) { case ConstraintLocator::ContextualType: { auto purpose = getContextualTypePurpose(); - assert(!(purpose == CTP_Unused && purpose == CTP_CannotFail)); + assert(!(purpose == CTP_Unused || purpose == CTP_CannotFail)); // If this is call to a closure e.g. `let _: A = { B() }()` // let's point diagnostic to its result. @@ -1977,7 +1978,7 @@ bool ContextualFailure::diagnoseAsError() { CTP = CTP_ClosureResult; } - if (auto msg = getDiagnosticFor(CTP, toType->isExistentialType())) { + if (auto msg = getDiagnosticFor(CTP, toType)) { diagnostic = *msg; break; } @@ -2085,6 +2086,7 @@ getContextualNilDiagnostic(ContextualTypePurpose CTP) { case CTP_EnumCaseRawValue: return diag::cannot_convert_raw_initializer_value_nil; case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: return diag::cannot_convert_default_arg_value_nil; case CTP_YieldByValue: return diag::cannot_convert_yield_value_nil; @@ -2276,11 +2278,9 @@ bool ContextualFailure::diagnoseCoercionToUnrelatedType() const { if (auto *coerceExpr = dyn_cast(anchor)) { auto fromType = getType(coerceExpr->getSubExpr()); auto toType = getType(coerceExpr->getCastTypeLoc()); - - auto diagnostic = - getDiagnosticFor(CTP_CoerceOperand, - /*forProtocol=*/toType->isExistentialType()); - + + auto diagnostic = getDiagnosticFor(CTP_CoerceOperand, toType); + auto diag = emitDiagnostic(anchor->getLoc(), *diagnostic, fromType, toType); diag.highlight(anchor->getSourceRange()); @@ -2844,26 +2844,40 @@ bool ContextualFailure::isIntegerToStringIndexConversion() const { Optional> ContextualFailure::getDiagnosticFor(ContextualTypePurpose context, - bool forProtocol) { + Type contextualType) { + auto forProtocol = contextualType->isExistentialType(); switch (context) { - case CTP_Initialization: + case CTP_Initialization: { + if (contextualType->isAnyObject()) + return diag::cannot_convert_initializer_value_anyobject; + return forProtocol ? diag::cannot_convert_initializer_value_protocol : diag::cannot_convert_initializer_value; + } case CTP_ReturnStmt: - case CTP_ReturnSingleExpr: + case CTP_ReturnSingleExpr: { + if (contextualType->isAnyObject()) + return diag::cannot_convert_return_type_to_anyobject; + return forProtocol ? diag::cannot_convert_to_return_type_protocol : diag::cannot_convert_to_return_type; + } case CTP_EnumCaseRawValue: return diag::cannot_convert_raw_initializer_value; case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: return forProtocol ? diag::cannot_convert_default_arg_value_protocol : diag::cannot_convert_default_arg_value; case CTP_YieldByValue: return forProtocol ? diag::cannot_convert_yield_value_protocol : diag::cannot_convert_yield_value; - case CTP_CallArgument: + case CTP_CallArgument: { + if (contextualType->isAnyObject()) + return diag::cannot_convert_argument_value_anyobject; + return forProtocol ? diag::cannot_convert_argument_value_protocol : diag::cannot_convert_argument_value; + } case CTP_ClosureResult: return forProtocol ? diag::cannot_convert_closure_result_protocol : diag::cannot_convert_closure_result; @@ -2879,9 +2893,13 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context, case CTP_CoerceOperand: return forProtocol ? diag::cannot_convert_coerce_protocol : diag::cannot_convert_coerce; - case CTP_AssignSource: + case CTP_AssignSource: { + if (contextualType->isAnyObject()) + return diag::cannot_convert_assign_anyobject; + return forProtocol ? diag::cannot_convert_assign_protocol : diag::cannot_convert_assign; + } case CTP_SubscriptAssignSource: return forProtocol ? diag::cannot_convert_subscript_assign_protocol : diag::cannot_convert_subscript_assign; @@ -2908,7 +2926,7 @@ bool TupleContextualFailure::diagnoseAsError() { else if ((purpose == CTP_Initialization) && !cs.getContextualType(getAnchor())) diagnostic = diag::tuple_types_not_convertible; - else if (auto diag = getDiagnosticFor(purpose, /*forProtocol=*/false)) + else if (auto diag = getDiagnosticFor(purpose, getToType())) diagnostic = *diag; else return false; @@ -2919,7 +2937,7 @@ bool TupleContextualFailure::diagnoseAsError() { bool FunctionTypeMismatch::diagnoseAsError() { auto purpose = getContextualTypePurpose(); - auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false); + auto diagnostic = getDiagnosticFor(purpose, getToType()); if (!diagnostic) return false; @@ -4839,17 +4857,16 @@ bool MissingContextualConformanceFailure::diagnoseAsError() { if (path.empty()) { assert(isa(anchor)); if (isa(cast(anchor)->getDest())) { - diagnostic = - getDiagnosticFor(CTP_SubscriptAssignSource, /*forProtocol=*/true); + diagnostic = getDiagnosticFor(CTP_SubscriptAssignSource, getToType()); } else { - diagnostic = getDiagnosticFor(CTP_AssignSource, /*forProtocol=*/true); + diagnostic = getDiagnosticFor(CTP_AssignSource, getToType()); } } else { const auto &last = path.back(); switch (last.getKind()) { case ConstraintLocator::ContextualType: assert(Context != CTP_Unused); - diagnostic = getDiagnosticFor(Context, /*forProtocol=*/true); + diagnostic = getDiagnosticFor(Context, getToType()); break; case ConstraintLocator::SequenceElementType: { @@ -5277,7 +5294,7 @@ bool InOutConversionFailure::diagnoseAsError() { assert(locator->findLast()); auto contextualType = cs.getContextualType(anchor); auto purpose = getContextualTypePurpose(); - auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false); + auto diagnostic = getDiagnosticFor(purpose, contextualType); if (!diagnostic) return false; @@ -5385,6 +5402,12 @@ bool ArgumentMismatchFailure::diagnoseAsError() { auto argType = getFromType(); auto paramType = getToType(); + if (paramType->isAnyObject()) { + emitDiagnostic(getLoc(), diag::cannot_convert_argument_value_anyobject, + argType, paramType); + return true; + } + Diag diagnostic = diag::cannot_convert_argument_value; // If parameter type is a protocol value, let's says that @@ -6117,3 +6140,45 @@ bool UnableToInferProtocolLiteralType::diagnoseAsError() { return true; } + +bool MissingQuialifierInMemberRefFailure::diagnoseAsError() { + auto selectedOverload = getOverloadChoiceIfAvailable(getLocator()); + if (!selectedOverload) + return false; + + auto *UDE = cast(getRawAnchor()); + + auto baseType = getType(UDE->getBase()); + + auto methodKind = baseType->isAnyExistentialType() + ? DescriptiveDeclKind::StaticMethod + : DescriptiveDeclKind::Method; + + auto choice = selectedOverload->choice.getDeclOrNull(); + if (!choice) + return false; + + auto *DC = choice->getDeclContext(); + if (!(DC->isModuleContext() || DC->isModuleScopeContext())) { + emitDiagnostic(UDE->getLoc(), diag::member_shadows_function, UDE->getName(), + methodKind, choice->getDescriptiveKind(), + choice->getFullName()); + return true; + } + + auto qualifier = DC->getParentModule()->getName(); + + emitDiagnostic(UDE->getLoc(), diag::member_shadows_global_function, + UDE->getName(), methodKind, choice->getDescriptiveKind(), + choice->getFullName(), qualifier); + + SmallString<32> namePlusDot = qualifier.str(); + namePlusDot.push_back('.'); + + emitDiagnostic(UDE->getLoc(), diag::fix_unqualified_access_top_level_multi, + namePlusDot, choice->getDescriptiveKind(), qualifier) + .fixItInsert(UDE->getStartLoc(), namePlusDot); + + emitDiagnostic(choice, diag::decl_declared_here, choice->getFullName()); + return true; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 90f64c5175acf..2f3c878a40777 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -653,7 +653,7 @@ class ContextualFailure : public FailureDiagnostic { ContextualTypePurpose getContextualTypePurpose() const { return CTP; } static Optional> - getDiagnosticFor(ContextualTypePurpose context, bool forProtocol); + getDiagnosticFor(ContextualTypePurpose context, Type contextualType); }; /// Diagnose errors related to converting function type which @@ -1936,6 +1936,29 @@ class UnableToInferProtocolLiteralType final : public FailureDiagnostic { bool diagnoseAsError(); }; +/// Diagnose an attempt to reference a top-level name shadowed by a local +/// member e.g. +/// +/// ```swift +/// extension Sequence { +/// func test() -> Int { +/// return max(1, 2) +/// } +/// } +/// ``` +/// +/// Here `max` refers to a global function `max(_: T, _: T)` in `Swift` +/// module and can only be accessed by adding `Swift.` to it, because `Sequence` +/// has a member named `max` which accepts a single argument. +class MissingQuialifierInMemberRefFailure final : public FailureDiagnostic { +public: + MissingQuialifierInMemberRefFailure(ConstraintSystem &cs, + ConstraintLocator *locator) + : FailureDiagnostic(cs, locator) {} + + bool diagnoseAsError(); +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index ffc4e502509a5..2eecf54297e86 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1180,3 +1180,52 @@ SpecifyObjectLiteralTypeImport::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyObjectLiteralTypeImport(cs, locator); } + +AllowNonClassTypeToConvertToAnyObject::AllowNonClassTypeToConvertToAnyObject( + ConstraintSystem &cs, Type type, ConstraintLocator *locator) + : ContextualMismatch(cs, FixKind::AllowNonClassTypeToConvertToAnyObject, + type, cs.getASTContext().getAnyObjectType(), locator) { +} + +bool AllowNonClassTypeToConvertToAnyObject::diagnose(bool asNote) const { + auto &cs = getConstraintSystem(); + + auto *locator = getLocator(); + if (locator->getPath().empty()) + return false; + + const auto &last = locator->getPath().back(); + switch (last.getKind()) { + case ConstraintLocator::ContextualType: { + ContextualFailure failure(cs, getFromType(), getToType(), locator); + return failure.diagnose(asNote); + } + + case ConstraintLocator::ApplyArgToParam: { + ArgumentMismatchFailure failure(cs, getFromType(), getToType(), locator); + return failure.diagnose(asNote); + } + + default: + return false; + } +} + +AllowNonClassTypeToConvertToAnyObject * +AllowNonClassTypeToConvertToAnyObject::create(ConstraintSystem &cs, Type type, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + AllowNonClassTypeToConvertToAnyObject(cs, type, locator); +} + +bool AddQualifierToAccessTopLevelName::diagnose(bool asNote) const { + auto &cs = getConstraintSystem(); + MissingQuialifierInMemberRefFailure failure(cs, getLocator()); + return failure.diagnose(asNote); +} + +AddQualifierToAccessTopLevelName * +AddQualifierToAccessTopLevelName::create(ConstraintSystem &cs, + ConstraintLocator *locator) { + return new (cs.getAllocator()) AddQualifierToAccessTopLevelName(cs, locator); +} diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 05959c8ddbaf4..d4c453070228d 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -235,12 +235,19 @@ enum class FixKind : uint8_t { /// Closure return type has to be explicitly specified because it can't be /// inferred in current context e.g. because it's a multi-statement closure. SpecifyClosureReturnType, - - /// Object literal type coudn't be infered because the module where + + /// Object literal type coudn't be inferred because the module where /// the default type that implements the associated literal protocol /// is declared was not imported. SpecifyObjectLiteralTypeImport, + /// Allow any type (and not just class or class-constrained type) to + /// be convertible to AnyObject. + AllowNonClassTypeToConvertToAnyObject, + + /// Member shadows a top-level name, such a name could only be accessed by + /// prefixing it with a module name. + AddQualifierToAccessTopLevelName, }; class ConstraintFix { @@ -1652,7 +1659,37 @@ class SpecifyObjectLiteralTypeImport final : public ConstraintFix { static SpecifyObjectLiteralTypeImport *create(ConstraintSystem &cs, ConstraintLocator *locator); +}; + +class AddQualifierToAccessTopLevelName final : public ConstraintFix { + AddQualifierToAccessTopLevelName(ConstraintSystem &cs, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::AddQualifierToAccessTopLevelName, locator) {} + +public: + std::string getName() const { + return "qualify reference to access top-level function"; + } + + bool diagnose(bool asNote = false) const; + + static AddQualifierToAccessTopLevelName *create(ConstraintSystem &cs, + ConstraintLocator *locator); +}; + +class AllowNonClassTypeToConvertToAnyObject final : public ContextualMismatch { + AllowNonClassTypeToConvertToAnyObject(ConstraintSystem &cs, Type type, + ConstraintLocator *locator); +public: + std::string getName() const { + return "allow non-class type to convert to 'AnyObject'"; + } + + bool diagnose(bool asNote = false) const; + + static AllowNonClassTypeToConvertToAnyObject * + create(ConstraintSystem &cs, Type type, ConstraintLocator *locator); }; } // end namespace constraints diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 3d00cf3de5a07..71d01c19f9c19 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2095,9 +2095,17 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2, // Subtype relation to AnyObject also allows class-bound // existentials that are not @objc and therefore carry // witness tables. - if (!type1->isClassExistentialType() && - !type1->mayHaveSuperclass()) + if (!type1->isClassExistentialType() && !type1->mayHaveSuperclass()) { + if (shouldAttemptFixes()) { + auto *fix = AllowNonClassTypeToConvertToAnyObject::create( + *this, type1, getConstraintLocator(locator)); + + return recordFix(fix) ? getTypeMatchFailure(locator) + : getTypeMatchSuccess(); + } + return getTypeMatchFailure(locator); + } } // Keep going. @@ -2152,6 +2160,17 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2, break; } + + // TODO(diagnostics): If there are any requirement failures associated + // with result types which are part of a function type conversion, + // let's record general conversion mismatch in order for it to capture + // and display complete function types. + // + // Once either reacher locators or better diagnostic presentation for + // nested type failures is available this check could be removed. + if (last->is()) + return getTypeMatchFailure(locator); + } else { // There are no elements in the path auto *anchor = locator.getAnchor(); if (!(anchor && @@ -3265,6 +3284,30 @@ bool ConstraintSystem::repairFailures( locator)) break; + { + auto *calleeLocator = getCalleeLocator(loc); + if (hasFixFor(calleeLocator, FixKind::AddQualifierToAccessTopLevelName)) { + if (auto overload = findSelectedOverloadFor(calleeLocator)) { + if (auto choice = overload->choice.getDeclOrNull()) { + // If this is an argument of a symetric function/operator let's + // not fix any position rather than first because we'd just end + // up with ambiguity instead of reporting an actual problem with + // mismatched type since each argument can have district bindings. + if (auto *AFD = dyn_cast(choice)) { + auto *paramList = AFD->getParameters(); + auto firstParamType = paramList->get(0)->getInterfaceType(); + if (elt.castTo().getParamIdx() > + 0 && + llvm::all_of(*paramList, [&](const ParamDecl *param) -> bool { + return param->getInterfaceType()->isEqual(firstParamType); + })) + return true; + } + } + } + } + } + conversionsOrFixes.push_back( AllowArgumentMismatch::create(*this, lhs, rhs, loc)); break; @@ -4060,16 +4103,12 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, auto result = matchTypes(instanceType1, instanceType2, subKind, subflags, locator.withPathElement(ConstraintLocator::InstanceType)); - if (shouldAttemptFixes() && result.isFailure()) { - auto *anchor = locator.getAnchor(); - if (anchor && isa(anchor)) { - auto *fix = - ContextualMismatch::create(*this, instanceType1, instanceType2, - getConstraintLocator(locator)); - conversionsOrFixes.push_back(fix); - break; - } - } + + // If matching of the instance types resulted in the failure make sure + // to give `repairFailure` a chance to run to attempt to fix the issue. + if (shouldAttemptFixes() && result.isFailure()) + break; + return result; } @@ -4079,21 +4118,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, auto result = matchFunctionTypes(func1, func2, kind, flags, locator); - if (shouldAttemptFixes() && result.isFailure()) { - // If this is a contextual type mismatch failure - // let's give the solver a chance to "fix" it. - if (auto last = locator.last()) { - if (last->is()) - break; - } - - // If this is a type mismatch in assignment, we don't really care - // (yet) was it argument or result type mismatch, let's produce a - // diagnostic which mentions both function types. - auto *anchor = locator.getAnchor(); - if (anchor && isa(anchor)) - break; - } + if (shouldAttemptFixes() && result.isFailure()) + break; return result; } @@ -6193,8 +6219,27 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( if (candidates.size() == 1) candidates.front()->setFavored(); - generateConstraints(candidates, memberTy, outerAlternatives, - useDC, locator); + // We *might* include any non-members that we found in outer contexts in + // some special cases, for backwards compatibility: first, we have to be + // looking for one of the special names ('min' or 'max'), and second, all + // of the inner (viable) results need to come from conditional + // conformances. The second condition is how the problem here was + // encountered: a type ('Range') was made to conditionally conform to a + // new protocol ('Sequence'), which introduced some extra methods + // ('min' and 'max') that shadowed global functions that people regularly + // called within extensions to that type (usually adding 'clamp'). + bool treatAsViable = + (member.isSimpleName("min") || member.isSimpleName("max")) && + allFromConditionalConformances(DC, baseTy, result.ViableCandidates); + + generateConstraints( + candidates, memberTy, outerAlternatives, useDC, locator, None, + /*requiresFix=*/!treatAsViable, + [&](unsigned, const OverloadChoice &) { + return treatAsViable ? nullptr + : AddQualifierToAccessTopLevelName::create( + *this, locator); + }); } } @@ -8842,7 +8887,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AllowMutatingMemberOnRValueBase: case FixKind::AllowTupleSplatForSingleParameter: case FixKind::AllowInvalidUseOfTrailingClosure: + case FixKind::AllowNonClassTypeToConvertToAnyObject: case FixKind::SpecifyClosureReturnType: + case FixKind::AddQualifierToAccessTopLevelName: llvm_unreachable("handled elsewhere"); } @@ -9127,6 +9174,7 @@ void ConstraintSystem::addContextualConversionConstraint( case CTP_ThrowStmt: case CTP_EnumCaseRawValue: case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: case CTP_ClosureResult: case CTP_DictionaryKey: case CTP_DictionaryValue: @@ -9306,7 +9354,12 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { case ConstraintKind::BindOverload: if (auto *fix = constraint.getFix()) { - if (recordFix(fix)) + // TODO(diagnostics): Impact should be associated with a fix unless + // it's a contextual problem, then only solver can decide what the impact + // would be in each particular situation. + auto impact = + fix->getKind() == FixKind::AddQualifierToAccessTopLevelName ? 10 : 1; + if (recordFix(fix, impact)) return SolutionKind::Error; } diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index fbae75e344bc2..9e8c3678a7f2f 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1074,7 +1074,8 @@ void ConstraintSystem::shrink(Expr *expr) { } } -static bool debugConstraintSolverForExpr(ASTContext &C, Expr *expr) { +static bool debugConstraintSolverForTarget( + ASTContext &C, SolutionApplicationTarget target) { if (C.TypeCheckerOpts.DebugConstraintSolver) return true; @@ -1082,14 +1083,13 @@ static bool debugConstraintSolverForExpr(ASTContext &C, Expr *expr) { // No need to compute the line number to find out it's not present. return false; - // Get the lines on which the expression starts and ends. + // Get the lines on which the target starts and ends. unsigned startLine = 0, endLine = 0; - if (expr->getSourceRange().isValid()) { - auto range = - Lexer::getCharSourceRangeFromSourceRange(C.SourceMgr, - expr->getSourceRange()); - startLine = C.SourceMgr.getLineNumber(range.getStart()); - endLine = C.SourceMgr.getLineNumber(range.getEnd()); + SourceRange range = target.getSourceRange(); + if (range.isValid()) { + auto charRange = Lexer::getCharSourceRangeFromSourceRange(C.SourceMgr, range); + startLine = C.SourceMgr.getLineNumber(charRange.getStart()); + endLine = C.SourceMgr.getLineNumber(charRange.getEnd()); } assert(startLine <= endLine && "expr ends before it starts?"); @@ -1107,25 +1107,44 @@ static bool debugConstraintSolverForExpr(ASTContext &C, Expr *expr) { return startBound != endBound; } -bool ConstraintSystem::solve(Expr *&expr, - Type convertType, - ExprTypeCheckListener *listener, - SmallVectorImpl &solutions, - FreeTypeVariableBinding allowFreeTypeVariables) { +/// If we aren't certain that we've emitted a diagnostic, emit a fallback +/// diagnostic. +static void maybeProduceFallbackDiagnostic( + ConstraintSystem &cs, SolutionApplicationTarget target) { + if (cs.Options.contains(ConstraintSystemFlags::SubExpressionDiagnostics) || + cs.Options.contains(ConstraintSystemFlags::SuppressDiagnostics)) + return; + + // Before producing fatal error here, let's check if there are any "error" + // diagnostics already emitted or waiting to be emitted. Because they are + // a better indication of the problem. + ASTContext &ctx = cs.getASTContext(); + if (ctx.Diags.hadAnyError() || ctx.hasDelayedConformanceErrors()) + return; + + ctx.Diags.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic); +} + +Optional> ConstraintSystem::solve( + SolutionApplicationTarget &target, + ExprTypeCheckListener *listener, + FreeTypeVariableBinding allowFreeTypeVariables +) { llvm::SaveAndRestore debugForExpr( getASTContext().TypeCheckerOpts.DebugConstraintSolver, - debugConstraintSolverForExpr(getASTContext(), expr)); + debugConstraintSolverForTarget(getASTContext(), target)); /// Dump solutions for debugging purposes. - auto dumpSolutions = [&] { + auto dumpSolutions = [&](const SolutionResult &result) { // Debug-print the set of solutions. if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); - if (solutions.size() == 1) { + if (result.getKind() == SolutionResult::Success) { log << "---Solution---\n"; - solutions[0].dump(log); - } else { - for (unsigned i = 0, e = solutions.size(); i != e; ++i) { + result.getSolution().dump(log); + } else if (result.getKind() == SolutionResult::Ambiguous) { + auto solutions = result.getAmbiguousSolutions(); + for (unsigned i : indices(solutions)) { log << "--- Solution #" << i << " ---\n"; solutions[i].dump(log); } @@ -1135,45 +1154,48 @@ bool ConstraintSystem::solve(Expr *&expr, // Take up to two attempts at solving the system. The first attempts to // solve a system that is expected to be well-formed, the second kicks in - // when there is an error and attempts to salvage an ill-formed expression. + // when there is an error and attempts to salvage an ill-formed program. for (unsigned stage = 0; stage != 2; ++stage) { auto solution = (stage == 0) - ? solveImpl(expr, convertType, listener, allowFreeTypeVariables) + ? solveImpl(target, listener, allowFreeTypeVariables) : salvage(); switch (solution.getKind()) { - case SolutionResult::Success: + case SolutionResult::Success: { // Return the successful solution. - solutions.clear(); - solutions.push_back(std::move(solution).takeSolution()); - dumpSolutions(); - return false; + dumpSolutions(solution); + std::vector result; + result.push_back(std::move(solution).takeSolution()); + return std::move(result); + } case SolutionResult::Error: - return true; + maybeProduceFallbackDiagnostic(*this, target); + return None; case SolutionResult::TooComplex: - getASTContext().Diags.diagnose(expr->getLoc(), diag::expression_too_complex) - .highlight(expr->getSourceRange()); + getASTContext().Diags.diagnose( + target.getLoc(), diag::expression_too_complex) + .highlight(target.getSourceRange()); solution.markAsDiagnosed(); - return true; + return None; case SolutionResult::Ambiguous: // If salvaging produced an ambiguous result, it has already been // diagnosed. if (stage == 1) { solution.markAsDiagnosed(); - return true; + return None; } if (Options.contains( ConstraintSystemFlags::AllowUnresolvedTypeVariables)) { + dumpSolutions(solution); auto ambiguousSolutions = std::move(solution).takeAmbiguousSolutions(); - solutions.assign(std::make_move_iterator(ambiguousSolutions.begin()), - std::make_move_iterator(ambiguousSolutions.end())); - dumpSolutions(); - solution.markAsDiagnosed(); - return false; + std::vector result( + std::make_move_iterator(ambiguousSolutions.begin()), + std::make_move_iterator(ambiguousSolutions.end())); + return std::move(result); } LLVM_FALLTHROUGH; @@ -1181,13 +1203,13 @@ bool ConstraintSystem::solve(Expr *&expr, case SolutionResult::UndiagnosedError: if (shouldSuppressDiagnostics()) { solution.markAsDiagnosed(); - return true; + return None; } if (stage == 1) { - diagnoseFailureFor(expr); + diagnoseFailureFor(target); solution.markAsDiagnosed(); - return true; + return None; } // Loop again to try to salvage. @@ -1200,14 +1222,13 @@ bool ConstraintSystem::solve(Expr *&expr, } SolutionResult -ConstraintSystem::solveImpl(Expr *&expr, - Type convertType, +ConstraintSystem::solveImpl(SolutionApplicationTarget &target, ExprTypeCheckListener *listener, FreeTypeVariableBinding allowFreeTypeVariables) { if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); - log << "---Constraint solving for the expression at "; - auto R = expr->getSourceRange(); + log << "---Constraint solving at "; + auto R = target.getSourceRange(); if (R.isValid()) { R.print(log, getASTContext().SourceMgr, /*PrintText=*/ false); } else { @@ -1219,6 +1240,7 @@ ConstraintSystem::solveImpl(Expr *&expr, assert(!solverState && "cannot be used directly"); // Set up the expression type checker timer. + Expr *expr = target.getAsExpr(); Timer.emplace(expr, *this); Expr *origExpr = expr; @@ -1232,14 +1254,12 @@ ConstraintSystem::solveImpl(Expr *&expr, if (auto generatedExpr = generateConstraints(expr, DC)) expr = generatedExpr; else { - if (listener) - listener->constraintGenerationFailed(expr); return SolutionResult::forError(); } // If there is a type that we're expected to convert to, add the conversion // constraint. - if (convertType) { + if (Type convertType = target.getExprConversionType()) { // Determine whether we know more about the contextual type. ContextualTypePurpose ctp = CTP_Unused; bool isOpaqueReturnType = false; @@ -1286,6 +1306,8 @@ ConstraintSystem::solveImpl(Expr *&expr, if (getExpressionTooComplex(solutions)) return SolutionResult::forTooComplex(); + target.setExpr(expr); + switch (solutions.size()) { case 0: return SolutionResult::forUndiagnosedError(); diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index a087a878ba1d5..85e8249f4c9bd 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -411,10 +411,8 @@ configureGenericDesignatedInitOverride(ASTContext &ctx, auto *gp = cast(type); if (gp->getDepth() < superclassDepth) return Type(gp).subst(subMap); - return CanGenericTypeParamType::get( - gp->getDepth() - superclassDepth + depth, - gp->getIndex(), - ctx); + return genericParams->getParams()[gp->getIndex()] + ->getDeclaredInterfaceType(); }; auto lookupConformanceFn = diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 472174e6de469..96c87701064b8 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -789,7 +789,7 @@ using OpenedTypeMap = /// Describes contextual type information about a particular expression /// within a constraint system. -struct ContextualTypeInfo { +struct ContextualTypeInfo { TypeLoc typeLoc; ContextualTypePurpose purpose; bool isOpaqueReturnType = false; @@ -1146,43 +1146,140 @@ class SolutionApplicationTarget { } kind; union { - Expr *expression; - AnyFunctionRef function; + struct { + Expr *expression; + + /// The purpose of the contextual type. + ContextualTypePurpose contextualPurpose; + + /// The type to which the expression should be converted. + TypeLoc convertType; + + /// Whether the expression result will be discarded at the end. + bool isDiscarded; + } expression; + + struct { + AnyFunctionRef function; + BraceStmt *body; + } function; }; public: - SolutionApplicationTarget(Expr *expr) { + SolutionApplicationTarget(Expr *expr, + ContextualTypePurpose contextualPurpose, + Type convertType, bool isDiscarded) + : SolutionApplicationTarget(expr, contextualPurpose, + TypeLoc::withoutLoc(convertType), + isDiscarded) { } + + SolutionApplicationTarget(Expr *expr, ContextualTypePurpose contextualPurpose, + TypeLoc convertType, bool isDiscarded) { kind = Kind::expression; - expression = expr; + expression.expression = expr; + expression.contextualPurpose = contextualPurpose; + expression.convertType = convertType; + expression.isDiscarded = isDiscarded; } - SolutionApplicationTarget(AnyFunctionRef fn) { + SolutionApplicationTarget(AnyFunctionRef fn) + : SolutionApplicationTarget(fn, fn.getBody()) { } + + SolutionApplicationTarget(AnyFunctionRef fn, BraceStmt *body) { kind = Kind::function; - function = fn; + function.function = fn; + function.body = body; } Expr *getAsExpr() const { switch (kind) { case Kind::expression: - return expression; + return expression.expression; case Kind::function: return nullptr; } } + ContextualTypePurpose getExprContextualTypePurpose() const { + assert(kind == Kind::expression); + return expression.contextualPurpose; + } + + Type getExprConversionType() const { + assert(kind == Kind::expression); + return expression.convertType.getType(); + } + + TypeLoc getExprConversionTypeLoc() const { + assert(kind == Kind::expression); + return expression.convertType; + } + + void setExprConversionType(Type type) { + assert(kind == Kind::expression); + expression.convertType = TypeLoc::withoutLoc(type); + } + + void setExprConversionTypeLoc(TypeLoc type) { + assert(kind == Kind::expression); + expression.convertType = type; + } + + bool isDiscardedExpr() const { + assert(kind == Kind::expression); + return expression.isDiscarded; + } + + void setExpr(Expr *expr) { + assert(kind == Kind::expression); + expression.expression = expr; + } + Optional getAsFunction() const { switch (kind) { case Kind::expression: return None; case Kind::function: - return function; + return function.function; + } + } + + BraceStmt *getFunctionBody() const { + assert(kind == Kind::function); + return function.body; + } + + void setFunctionBody(BraceStmt *stmt) { + assert(kind == Kind::function); + function.body = stmt; + } + + /// Retrieve the source range of the target. + SourceRange getSourceRange() const { + switch (kind) { + case Kind::expression: + return expression.expression->getSourceRange(); + + case Kind::function: + return function.body->getSourceRange(); + } + } + + /// Retrieve the source location for the target. + SourceLoc getLoc() const { + switch (kind) { + case Kind::expression: + return expression.expression->getLoc(); + + case Kind::function: + return function.function.getLoc(); } } /// Walk the contents of the application target. - llvm::PointerUnion walk(ASTWalker &walker); + SolutionApplicationTarget walk(ASTWalker &walker); }; enum class ConstraintSystemPhase { @@ -4036,13 +4133,11 @@ class ConstraintSystem { /// Solve the system of constraints generated from provided expression. /// - /// \param expr The expression to generate constraints from. - /// \param convertType The expected type of the expression. + /// \param target The target to generate constraints from. /// \param listener The callback to check solving progress. /// \param allowFreeTypeVariables How to bind free type variables in /// the solution. - SolutionResult solveImpl(Expr *&expr, - Type convertType, + SolutionResult solveImpl(SolutionApplicationTarget &target, ExprTypeCheckListener *listener, FreeTypeVariableBinding allowFreeTypeVariables = FreeTypeVariableBinding::Disallow); @@ -4053,26 +4148,21 @@ class ConstraintSystem { static bool preCheckExpression(Expr *&expr, DeclContext *dc, ConstraintSystem *baseCS = nullptr); - /// Solve the system of constraints generated from provided expression. + /// Solve the system of constraints generated from provided target. /// - /// The expression should have already been pre-checked with - /// preCheckExpression(). - /// - /// \param expr The expression to generate constraints from. - /// \param convertType The expected type of the expression. + /// \param target The target that we'll generate constraints from, which + /// may be updated by the solving process. /// \param listener The callback to check solving progress. - /// \param solutions The set of solutions to the system of constraints. /// \param allowFreeTypeVariables How to bind free type variables in /// the solution. /// - /// \returns true is an error occurred, false is system is consistent - /// and solutions were found. - bool solve(Expr *&expr, - Type convertType, - ExprTypeCheckListener *listener, - SmallVectorImpl &solutions, - FreeTypeVariableBinding allowFreeTypeVariables - = FreeTypeVariableBinding::Disallow); + /// \returns the set of solutions, if any were found, or \c None if an + /// error occurred. When \c None, an error has been emitted. + Optional> solve( + SolutionApplicationTarget &target, + ExprTypeCheckListener *listener, + FreeTypeVariableBinding allowFreeTypeVariables + = FreeTypeVariableBinding::Disallow); /// Solve the system of constraints. /// @@ -4146,35 +4236,16 @@ class ConstraintSystem { findBestSolution(SmallVectorImpl &solutions, bool minimize); -private: - llvm::PointerUnion applySolutionImpl( - Solution &solution, SolutionApplicationTarget target, - Type convertType, bool discardedExpr, bool performingDiagnostics); - public: - /// Apply a given solution to the expression, producing a fully - /// type-checked expression. + /// Apply a given solution to the target, producing a fully + /// type-checked target or \c None if an error occurred. /// - /// \param convertType the contextual type to which the - /// expression should be converted, if any. - /// \param discardedExpr if true, the result of the expression - /// is contextually ignored. + /// \param target the target to which the solution will be applied. /// \param performingDiagnostics if true, don't descend into bodies of /// non-single expression closures, or build curry thunks. - Expr *applySolution(Solution &solution, Expr *expr, - Type convertType, - bool discardedExpr, - bool performingDiagnostics) { - return applySolutionImpl(solution, expr, convertType, discardedExpr, - performingDiagnostics).get(); - } - - /// Apply a given solution to the body of the given function. - BraceStmt *applySolutionToBody(Solution &solution, AnyFunctionRef fn) { - return cast_or_null( - applySolutionImpl(solution, fn, Type(), false, false) - .dyn_cast()); - } + Optional applySolution( + Solution &solution, SolutionApplicationTarget target, + bool performingDiagnostics); /// Reorder the disjunctive clauses for a given expression to /// increase the likelihood that a favored constraint will be successfully diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index de6d54af3adce..2d05095eb2e55 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -452,20 +452,6 @@ static bool findNonMembers(ArrayRef lookupResults, return AllDeclRefs; } -/// Whether we should be looking at the outer results for a function called \c -/// name. -/// -/// This is very restrictive because it's a source compatibility issue (see the -/// if (AllConditionalConformances) { (void)findNonMembers(...); } below). -static bool shouldConsiderOuterResultsFor(DeclNameRef name) { - const StringRef specialNames[] = {"min", "max"}; - for (auto specialName : specialNames) - if (name.isSimpleName(specialName)) - return true; - - return false; -} - /// Bind an UnresolvedDeclRefExpr by performing name lookup and /// returning the resultant expression. Context is the DeclContext used /// for the lookup. @@ -479,8 +465,11 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions; if (isa(DC)) lookupOptions |= NameLookupFlags::KnownPrivate; - if (shouldConsiderOuterResultsFor(Name)) - lookupOptions |= NameLookupFlags::IncludeOuterResults; + + // TODO: Include all of the possible members to give a solver a + // chance to diagnose name shadowing which requires explicit + // name/module qualifier to access top-level name. + lookupOptions |= NameLookupFlags::IncludeOuterResults; auto Lookup = TypeChecker::lookupUnqualified(DC, Name, Loc, lookupOptions); @@ -625,14 +614,6 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, // better matching candidates. if (localDeclAfterUse) { auto innerDecl = localDeclAfterUse; - - // Perform a thorough lookup if outer results was not included before. - if (!lookupOptions.contains(NameLookupFlags::IncludeOuterResults)) { - auto option = lookupOptions; - option |= NameLookupFlags::IncludeOuterResults; - Lookup = lookupUnqualified(DC, Name, Loc, option); - } - while (localDeclAfterUse) { if (Lookup.outerResults().empty()) { Context.Diags.diagnose(Loc, diag::use_local_before_declaration, Name); @@ -649,13 +630,6 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, findNonMembers(Lookup.innerResults(), UDRE->getRefKind(), /*breakOnMember=*/true, ResultValues, isValid); } - - // Drop outer results if they are not supposed to be included. - if (!lookupOptions.contains(NameLookupFlags::IncludeOuterResults)) { - Lookup.filter([&](LookupResultEntry Result, bool isOuter) { - return !isOuter; - }); - } } // If we have an unambiguous reference to a type decl, form a TypeExpr. @@ -715,7 +689,6 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, ResultValues.clear(); bool AllMemberRefs = true; - bool AllConditionalConformances = true; ValueDecl *Base = nullptr; DeclContext *BaseDC = nullptr; for (auto Result : Lookup) { @@ -732,26 +705,6 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, Base = ThisBase; BaseDC = Result.getDeclContext(); - - // Check if this result is derived through a conditional conformance, - // meaning it comes from a protocol (or extension) where there's a - // conditional conformance for the type with the method in question - // (NB. that type may not be the type associated with DC, for tested types - // with static methods). - if (auto Proto = Value->getDeclContext()->getSelfProtocolDecl()) { - auto contextSelfType = - BaseDC->getInnermostTypeContext()->getDeclaredInterfaceType(); - auto conformance = conformsToProtocol( - contextSelfType, Proto, DC, - ConformanceCheckFlags::InExpression | - ConformanceCheckFlags::SkipConditionalRequirements); - - if (conformance.isInvalid() || - conformance.getConditionalRequirements().empty()) { - AllConditionalConformances = false; - } - } - continue; } @@ -774,22 +727,12 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, /*Implicit=*/true); } - // We *might* include any non-members that we found in outer contexts in - // some special cases, for backwards compatibility: first, we have to be - // looking for one of the special names - // ('shouldConsiderOuterResultsFor(Name)'), and second, all of the inner - // results need to come from conditional conformances. The second condition - // is how the problem here was encountered: a type ('Range') was made to - // conditionally conform to a new protocol ('Sequence'), which introduced - // some extra methods ('min' and 'max') that shadowed global functions that - // people regularly called within extensions to that type (usually adding - // 'clamp'). llvm::SmallVector outerAlternatives; - if (AllConditionalConformances) { - (void)findNonMembers(Lookup.outerResults(), UDRE->getRefKind(), - /*breakOnMember=*/false, outerAlternatives, - /*isValid=*/[&](ValueDecl *) { return true; }); - } + (void)findNonMembers(Lookup.outerResults(), UDRE->getRefKind(), + /*breakOnMember=*/false, outerAlternatives, + /*isValid=*/[](ValueDecl *choice) -> bool { + return !choice->isInvalid(); + }); // Otherwise, form an UnresolvedDotExpr and sema will resolve it based on // type information. @@ -2027,19 +1970,10 @@ bool ExprTypeCheckListener::builtConstraints(ConstraintSystem &cs, Expr *expr) { return false; } -Expr *ExprTypeCheckListener::foundSolution(Solution &solution, Expr *expr) { - return expr; -} - Expr *ExprTypeCheckListener::appliedSolution(Solution &solution, Expr *expr) { return expr; } -void ExprTypeCheckListener::preCheckFailed(Expr *expr) {} -void ExprTypeCheckListener::constraintGenerationFailed(Expr *expr) {} -void ExprTypeCheckListener::applySolutionFailed(Solution &solution, - Expr *expr) {} - void ParentConditionalConformance::diagnoseConformanceStack( DiagnosticEngine &diags, SourceLoc loc, ArrayRef conformances) { @@ -2067,88 +2001,39 @@ bool GenericRequirementsCheckListener::diagnoseUnsatisfiedRequirement( return false; } -/// Sometimes constraint solver fails without producing any diagnostics, -/// that leads to crashes down the line in AST Verifier or SILGen -/// which, as a result, are much harder to figure out. -/// -/// This class is intended to guard against situations like that by -/// keeping track of failures of different type-check phases, and -/// emitting fallback fatal error if any of them fail without producing -/// error diagnostic, and there were no errors emitted or scheduled to be -/// emitted previously. -class FallbackDiagnosticListener : public ExprTypeCheckListener { - ASTContext &Context; - TypeCheckExprOptions Options; - ExprTypeCheckListener *BaseListener; - -public: - FallbackDiagnosticListener(ASTContext &ctx, TypeCheckExprOptions options, - ExprTypeCheckListener *base) - : Context(ctx), Options(options), BaseListener(base) {} - - bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { - return BaseListener ? BaseListener->builtConstraints(cs, expr) : false; - } - - Expr *foundSolution(Solution &solution, Expr *expr) override { - return BaseListener ? BaseListener->foundSolution(solution, expr) : expr; - } - - Expr *appliedSolution(Solution &solution, Expr *expr) override { - return BaseListener ? BaseListener->appliedSolution(solution, expr) : expr; - } - - void preCheckFailed(Expr *expr) override { - if (BaseListener) - BaseListener->preCheckFailed(expr); - maybeProduceFallbackDiagnostic(expr); - } - - void constraintGenerationFailed(Expr *expr) override { - if (BaseListener) - BaseListener->constraintGenerationFailed(expr); - maybeProduceFallbackDiagnostic(expr); - } - - void applySolutionFailed(Solution &solution, Expr *expr) override { - if (BaseListener) - BaseListener->applySolutionFailed(solution, expr); - - if (hadAnyErrors()) - return; - - // If solution involves invalid or incomplete conformances that's - // a probable cause of failure to apply it without producing an error, - // which is going to be diagnosed later, so let's not produce - // fallback diagnostic in this case. - if (llvm::any_of( - solution.Conformances, - [](const std::pair - &conformance) -> bool { - auto &ref = conformance.second; - return ref.isConcrete() && ref.getConcrete()->isInvalid(); - })) - return; - - maybeProduceFallbackDiagnostic(expr); - } - -private: - bool hadAnyErrors() const { return Context.Diags.hadAnyError(); } - - void maybeProduceFallbackDiagnostic(Expr *expr) const { - if (Options.contains(TypeCheckExprFlags::SubExpressionDiagnostics) || - DiagnosticSuppression::isEnabled(Context.Diags)) - return; - - // Before producing fatal error here, let's check if there are any "error" - // diagnostics already emitted or waiting to be emitted. Because they are - // a better indication of the problem. - if (!(hadAnyErrors() || Context.hasDelayedConformanceErrors())) - Context.Diags.diagnose(expr->getLoc(), - diag::failed_to_produce_diagnostic); +/// Whether the contextual type provided for the given purpose is only a +/// hint, and not a requirement. +static bool contextualTypeIsOnlyAHint(ContextualTypePurpose ctp, + TypeCheckExprOptions options) { + switch (ctp) { + case CTP_Initialization: + return !options.contains( + TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType); + case CTP_ForEachStmt: + return true; + case CTP_Unused: + case CTP_ReturnStmt: + case CTP_ReturnSingleExpr: + case CTP_YieldByValue: + case CTP_YieldByReference: + case CTP_ThrowStmt: + case CTP_EnumCaseRawValue: + case CTP_DefaultParameter: + case CTP_AutoclosureDefaultParameter: + case CTP_CalleeResult: + case CTP_CallArgument: + case CTP_ClosureResult: + case CTP_ArrayElement: + case CTP_DictionaryKey: + case CTP_DictionaryValue: + case CTP_CoerceOperand: + case CTP_AssignSource: + case CTP_SubscriptAssignSource: + case CTP_Condition: + case CTP_CannotFail: + return false; } -}; +} #pragma mark High-level entry points Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc, @@ -2158,25 +2043,12 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc, ExprTypeCheckListener *listener, ConstraintSystem *baseCS) { auto &Context = dc->getASTContext(); - FallbackDiagnosticListener diagListener(Context, options, listener); - return typeCheckExpressionImpl(expr, dc, convertType, convertTypePurpose, - options, diagListener, baseCS); -} - -Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, - TypeLoc convertType, - ContextualTypePurpose convertTypePurpose, - TypeCheckExprOptions options, - ExprTypeCheckListener &listener, - ConstraintSystem *baseCS) { - auto &Context = dc->getASTContext(); FrontendStatsTracer StatsTracer(Context.Stats, "typecheck-expr", expr); PrettyStackTraceExpr stackTrace(Context, "type-checking", expr); // First, pre-check the expression, validating any types that occur in the // expression and folding sequence expressions. if (ConstraintSystem::preCheckExpression(expr, dc, baseCS)) { - listener.preCheckFailed(expr); return Type(); } @@ -2212,6 +2084,14 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, } } + // For an @autoclosure default parameter, we want to convert to the result + // type. Stash the autoclosure default parameter type. + FunctionType *autoclosureDefaultParamType = nullptr; + if (convertTypePurpose == CTP_AutoclosureDefaultParameter) { + autoclosureDefaultParamType = convertType.getType()->castTo(); + convertType.setType(autoclosureDefaultParamType->getResult()); + } + // Tell the constraint system what the contextual type is. This informs // diagnostics and is a hint for various performance optimizations. // FIXME: Look through LoadExpr. This is an egregious hack due to the @@ -2225,7 +2105,7 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, // If the convertType is *only* provided for that hint, then null it out so // that we don't later treat it as an actual conversion constraint. - if (options.contains(TypeCheckExprFlags::ConvertTypeIsOnlyAHint)) + if (contextualTypeIsOnlyAHint(convertTypePurpose, options)) convertType = TypeLoc(); // If the client can handle unresolved type variables, leave them in the @@ -2235,6 +2115,7 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, allowFreeTypeVariables = FreeTypeVariableBinding::UnresolvedType; Type convertTo = convertType.getType(); + if (options.contains(TypeCheckExprFlags::ExpressionTypeMustBeOptional)) { assert(!convertTo && "convertType and type check options conflict"); auto *convertTypeLocator = @@ -2243,23 +2124,25 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, convertTo = getOptionalType(expr->getLoc(), var); } - SmallVector viable; // Attempt to solve the constraint system. - if (cs.solve(expr, convertTo, &listener, viable, allowFreeTypeVariables)) + SolutionApplicationTarget target( + expr, convertTypePurpose, convertTo, + options.contains(TypeCheckExprFlags::IsDiscarded)); + auto viable = cs.solve(target, listener, allowFreeTypeVariables); + if (!viable) return Type(); // If the client allows the solution to have unresolved type expressions, // check for them now. We cannot apply the solution with unresolved TypeVars, // because they will leak out into arbitrary places in the resultant AST. if (options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables) && - (viable.size() != 1 || + (viable->size() != 1 || (convertType.getType() && convertType.getType()->hasUnresolvedType()))) { return ErrorType::get(Context); } - auto result = expr; - auto &solution = viable[0]; - result = listener.foundSolution(solution, result); + auto result = target.getAsExpr(); + auto &solution = (*viable)[0]; if (!result) return Type(); @@ -2267,19 +2150,26 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, cs.applySolution(solution); // Apply the solution to the expression. - result = cs.applySolution( - solution, result, convertType.getType(), - options.contains(TypeCheckExprFlags::IsDiscarded), - options.contains(TypeCheckExprFlags::SubExpressionDiagnostics)); - - if (!result) { - listener.applySolutionFailed(solution, expr); + bool performingDiagnostics = + options.contains(TypeCheckExprFlags::SubExpressionDiagnostics); + // FIXME: HACK! + target.setExprConversionType(convertType.getType()); + auto resultTarget = cs.applySolution(solution, target, performingDiagnostics); + if (!resultTarget) { // Failure already diagnosed, above, as part of applying the solution. return Type(); } + result = resultTarget->getAsExpr(); + + // For an @autoclosure default parameter type, add the autoclosure + // conversion. + if (convertTypePurpose == CTP_AutoclosureDefaultParameter) { + result = cs.buildAutoClosureExpr(result, autoclosureDefaultParamType); + } // Notify listener that we've applied the solution. - result = listener.appliedSolution(solution, result); + if (listener) + result = listener->appliedSolution(solution, result); if (!result) return Type(); @@ -2293,7 +2183,7 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, // Unless the client has disabled them, perform syntactic checks on the // expression now. if (!cs.shouldSuppressDiagnostics() && - !options.contains(TypeCheckExprFlags::DisableStructuralChecks)) { + !options.contains(TypeCheckExprFlags::SubExpressionDiagnostics)) { bool isExprStmt = options.contains(TypeCheckExprFlags::IsExprStmt); performSyntacticExprDiagnostics(result, dc, isExprStmt); } @@ -2306,32 +2196,9 @@ Type TypeChecker::typeCheckParameterDefault(Expr *&defaultValue, DeclContext *DC, Type paramType, bool isAutoClosure) { assert(paramType && !paramType->hasError()); - - if (isAutoClosure) { - class AutoClosureListener : public ExprTypeCheckListener { - FunctionType *ParamType; - - public: - AutoClosureListener(FunctionType *paramType) - : ParamType(paramType) {} - - Expr *appliedSolution(constraints::Solution &solution, - Expr *expr) override { - auto &cs = solution.getConstraintSystem(); - return cs.buildAutoClosureExpr(expr, ParamType); - } - }; - - auto *fnType = paramType->castTo(); - AutoClosureListener listener(fnType); - return typeCheckExpression(defaultValue, DC, - TypeLoc::withoutLoc(fnType->getResult()), - CTP_DefaultParameter, TypeCheckExprOptions(), - &listener); - } - - return typeCheckExpression(defaultValue, DC, TypeLoc::withoutLoc(paramType), - CTP_DefaultParameter); + return typeCheckExpression( + defaultValue, DC, TypeLoc::withoutLoc(paramType), + isAutoClosure ? CTP_AutoclosureDefaultParameter : CTP_DefaultParameter); } Type TypeChecker:: @@ -2348,7 +2215,6 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc, ConstraintSystem cs(dc, ConstraintSystemFlags::SuppressDiagnostics); // Attempt to solve the constraint system. - SmallVector viable; const Type originalType = expr->getType(); const bool needClearType = originalType && originalType->hasError(); const auto recoverOriginalType = [&] () { @@ -2360,14 +2226,17 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc, // re-check. if (needClearType) expr->setType(Type()); - if (cs.solve(expr, /*convertType*/Type(), listener, viable, - allowFreeTypeVariables)) { + SolutionApplicationTarget target( + expr, CTP_Unused, Type(), /*isDiscarded=*/false); + auto viable = cs.solve(target, listener, allowFreeTypeVariables); + if (!viable) { recoverOriginalType(); return Type(); } // Get the expression's simplified type. - auto &solution = viable[0]; + expr = target.getAsExpr(); + auto &solution = (*viable)[0]; auto &solutionCS = solution.getConstraintSystem(); Type exprType = solution.simplifyType(solutionCS.getType(expr)); @@ -2434,19 +2303,19 @@ void TypeChecker::getPossibleTypesOfExpressionWithoutApplying( ConstraintSystem cs(dc, options); // Attempt to solve the constraint system. - SmallVector viable; - const Type originalType = expr->getType(); if (originalType && originalType->hasError()) expr->setType(Type()); - cs.solve(expr, /*convertType*/ Type(), listener, viable, - allowFreeTypeVariables); - - for (auto &solution : viable) { - auto exprType = solution.simplifyType(cs.getType(expr)); - assert(exprType && !exprType->hasTypeVariable()); - types.insert(exprType.getPointer()); + SolutionApplicationTarget target( + expr, CTP_Unused, Type(), /*isDiscarded=*/false); + if (auto viable = cs.solve(target, listener, allowFreeTypeVariables)) { + expr = target.getAsExpr(); + for (auto &solution : *viable) { + auto exprType = solution.simplifyType(cs.getType(expr)); + assert(exprType && !exprType->hasTypeVariable()); + types.insert(exprType.getPointer()); + } } } @@ -2676,16 +2545,13 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer, return false; } - Expr *foundSolution(Solution &solution, Expr *expr) override { - // Figure out what type the constraints decided on. - auto ty = solution.simplifyType(initType); - initType = ty->getRValueType()->reconstituteSugar(/*recursive =*/false); - - // Just keep going. - return expr; - } - Expr *appliedSolution(Solution &solution, Expr *expr) override { + { + // Figure out what type the constraints decided on. + auto ty = solution.simplifyType(initType); + initType = ty->getRValueType()->reconstituteSugar(/*recursive =*/false); + } + // Convert the initializer to the type of the pattern. expr = solution.coerceToType(expr, initType, Locator); if (!expr) @@ -2768,7 +2634,7 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer, TypeLoc contextualType; auto contextualPurpose = CTP_Unused; - TypeCheckExprOptions flags = TypeCheckExprFlags::ConvertTypeIsOnlyAHint; + TypeCheckExprOptions flags = None; // Set the contextual purpose even if the pattern doesn't have a type so // if there's an error we can use that information to inform diagnostics. @@ -2787,7 +2653,6 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer, // opaque type. if (auto opaqueType = patternType->getAs()){ flags |= TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType; - flags -= TypeCheckExprFlags::ConvertTypeIsOnlyAHint; } // Only provide a TypeLoc if it makes sense to allow diagnostics. @@ -3155,7 +3020,7 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) { // Type-check the for-each loop sequence and element pattern. auto resultTy = TypeChecker::typeCheckExpression( seq, dc, TypeLoc::withoutLoc(sequenceProto->getDeclaredType()), - CTP_ForEachStmt, TypeCheckExprFlags::ConvertTypeIsOnlyAHint, &listener); + CTP_ForEachStmt, None, &listener); if (!resultTy) return true; return false; @@ -3314,30 +3179,7 @@ bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, /*Implicit=*/true); // Check the expression as a condition. - // - // TODO: Type-check of `~=` operator can't (yet) use `typeCheckCondition` - // because that utilizes contextual type which interferes with diagnostics. - // We don't yet have a full access to pattern-matching context in - // constraint system, which is required to enable these situations - // to be properly diagnosed. - struct ConditionListener : public ExprTypeCheckListener { - // Add the appropriate Boolean constraint. - bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { - // Otherwise, the result must be convertible to Bool. - auto boolDecl = cs.getASTContext().getBoolDecl(); - if (!boolDecl) - return true; - - // Condition must convert to Bool. - cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), - boolDecl->getDeclaredType(), - cs.getConstraintLocator(expr)); - return false; - } - }; - - ConditionListener listener; - bool hadError = !typeCheckExpression(matchCall, DC, &listener); + bool hadError = typeCheckCondition(matchCall, DC); // Save the type-checked expression in the pattern. EP->setMatchExpr(matchCall); // Set the type on the pattern. diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index cb4f75303721a..5659c6f8912aa 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1336,13 +1336,13 @@ class DeclChecker : public DeclVisitor { } if (VD->getDeclContext()->getSelfClassDecl()) { - checkDynamicSelfType(VD, VD->getValueInterfaceType()); - if (VD->getValueInterfaceType()->hasDynamicSelfType()) { if (VD->hasStorage()) VD->diagnose(diag::dynamic_self_in_stored_property); else if (VD->isSettable(nullptr)) VD->diagnose(diag::dynamic_self_in_mutable_property); + else + checkDynamicSelfType(VD, VD->getValueInterfaceType()); } } @@ -2153,8 +2153,11 @@ class DeclChecker : public DeclVisitor { checkExplicitAvailability(FD); - if (FD->getDeclContext()->getSelfClassDecl()) - checkDynamicSelfType(FD, FD->getResultInterfaceType()); + // Skip this for accessors, since we should have diagnosed the + // storage itself. + if (!isa(FD)) + if (FD->getDeclContext()->getSelfClassDecl()) + checkDynamicSelfType(FD, FD->getResultInterfaceType()); checkDefaultArguments(FD->getParameters()); diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 7ad524f45df3f..707d454122c5e 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -195,6 +195,12 @@ namespace { addResult(found); return; } + } else if (isa(found)) { + // Declaring nested types inside other types is currently + // not supported by lookup would still return such members + // so we have to account for that here as well. + addResult(found); + return; } // FIXME: the "isa()" check will be wrong for diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index ad3ab2f99e947..483c9db23cb4d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1463,10 +1463,6 @@ static Type resolveNestedIdentTypeComponent( inferredAssocType); } - // At this point, we need to have resolved the type of the member. - if (memberType->hasError()) - return memberType; - // If there are generic arguments, apply them now. return applyGenericArguments(memberType, resolution, comp, options); }; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index c4df6c61bb254..47e4aef224621 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -133,6 +133,10 @@ enum ContextualTypePurpose { CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum. CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'. + /// Default value in @autoclosure parameter + /// 'foo(a : @autoclosure () -> Int = 42)'. + CTP_AutoclosureDefaultParameter, + CTP_CalleeResult, ///< Constraint is placed on the result of a callee. CTP_CallArgument, ///< Call to function or operator requires type. CTP_ClosureResult, ///< Closure result expects a specific type. @@ -159,10 +163,6 @@ enum class TypeCheckExprFlags { /// disables constraints forcing an lvalue result to be loadable. IsDiscarded = 0x01, - /// Whether the client wants to disable the structural syntactic restrictions - /// that we force for style or other reasons. - DisableStructuralChecks = 0x02, - /// If set, the client wants a best-effort solution to the constraint system, /// but can tolerate a solution where all of the constraints are solved, but /// not all type variables have been determined. In this case, the constraint @@ -170,20 +170,11 @@ enum class TypeCheckExprFlags { /// left in-tact. AllowUnresolvedTypeVariables = 0x08, - /// If set, the 'convertType' specified to typeCheckExpression should not - /// produce a conversion constraint, but it should be used to guide the - /// solution in terms of performance optimizations of the solver, and in terms - /// of guiding diagnostics. - ConvertTypeIsOnlyAHint = 0x10, - /// If set, this expression isn't embedded in a larger expression or /// statement. This should only be used for syntactic restrictions, and should /// not affect type checking itself. IsExprStmt = 0x20, - /// This is an inout yield. - IsInOutYield = 0x100, - /// If set, a conversion constraint should be specified so that the result of /// the expression is an optional type. ExpressionTypeMustBeOptional = 0x200, @@ -305,13 +296,6 @@ class ExprTypeCheckListener { /// constraint system, or false otherwise. virtual bool builtConstraints(constraints::ConstraintSystem &cs, Expr *expr); - /// Callback invoked once a solution has been found. - /// - /// The callback may further alter the expression, returning either a - /// new expression (to replace the result) or a null pointer to indicate - /// failure. - virtual Expr *foundSolution(constraints::Solution &solution, Expr *expr); - /// Callback invokes once the chosen solution has been applied to the /// expression. /// @@ -320,18 +304,6 @@ class ExprTypeCheckListener { /// failure. virtual Expr *appliedSolution(constraints::Solution &solution, Expr *expr); - - /// Callback invoked if expression is structurally unsound and can't - /// be correctly processed by the constraint solver. - virtual void preCheckFailed(Expr *expr); - - /// Callback invoked if constraint system failed to generate - /// constraints for a given expression. - virtual void constraintGenerationFailed(Expr *expr); - - /// Callback invoked if application of chosen solution to - /// expression has failed. - virtual void applySolutionFailed(constraints::Solution &solution, Expr *expr); }; /// A conditional conformance that implied some other requirements. That is, \c @@ -836,11 +808,9 @@ class TypeChecker final { /// to be possible. /// /// \param convertType The type that the expression is being converted to, - /// or null if the expression is standalone. If the 'ConvertTypeIsOnlyAHint' - /// option is specified, then this is only a hint, it doesn't produce a full - /// conversion constraint. The location information is only used for - /// diagnostics should the conversion fail; it is safe to pass a TypeLoc - /// without location information. + /// or null if the expression is standalone. The location information is + /// only used for diagnostics should the conversion fail; it is safe to pass + /// a TypeLoc without location information. /// /// \param options Options that control how type checking is performed. /// @@ -862,21 +832,6 @@ class TypeChecker final { ExprTypeCheckListener *listener = nullptr, constraints::ConstraintSystem *baseCS = nullptr); - static Type typeCheckExpression(Expr *&expr, DeclContext *dc, - ExprTypeCheckListener *listener) { - return TypeChecker::typeCheckExpression(expr, dc, TypeLoc(), CTP_Unused, - TypeCheckExprOptions(), listener); - } - -private: - static Type typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, - TypeLoc convertType, - ContextualTypePurpose convertTypePurpose, - TypeCheckExprOptions options, - ExprTypeCheckListener &listener, - constraints::ConstraintSystem *baseCS); - -public: /// Type check the given expression and return its type without /// applying the solution. /// diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 4c62bb3728b1a..78d5bed929e30 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1468,6 +1468,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { if (auto overlayModule = LF->getOverlayModule()) { nestedType = findNestedTypeDeclInModule(getFile(), overlayModule, memberName, baseType); + } else if (LF->getParentModule() != extensionModule) { + nestedType = findNestedTypeDeclInModule(getFile(), + LF->getParentModule(), + memberName, baseType); } } } @@ -2657,6 +2661,7 @@ class DeclDeserializer { uint8_t rawIntroducer; bool isGetterMutating, isSetterMutating; bool isLazyStorageProperty; + bool isTopLevelGlobal; DeclID lazyStorageID; unsigned numAccessors, numBackingProperties; uint8_t readImpl, writeImpl, readWriteImpl, opaqueReadOwnership; @@ -2673,6 +2678,7 @@ class DeclDeserializer { hasNonPatternBindingInit, isGetterMutating, isSetterMutating, isLazyStorageProperty, + isTopLevelGlobal, lazyStorageID, opaqueReadOwnership, readImpl, writeImpl, readWriteImpl, @@ -2804,6 +2810,7 @@ class DeclDeserializer { } var->setLazyStorageProperty(isLazyStorageProperty); + var->setTopLevelGlobal(isTopLevelGlobal); // If there are any backing properties, record them. if (numBackingProperties > 0) { diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 265ea709a7c89..c2769a9c5ef97 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 534; // add SIL parameter differentiability +const uint16_t SWIFTMODULE_VERSION_MINOR = 535; // top-level var decls /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1191,6 +1191,7 @@ namespace decls_block { BCFixed<1>, // is getter mutating? BCFixed<1>, // is setter mutating? BCFixed<1>, // is this the backing storage for a lazy property? + BCFixed<1>, // top level global? DeclIDField, // if this is a lazy property, this is the backing storage OpaqueReadOwnershipField, // opaque read ownership ReadImplKindField, // read implementation diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index ce49f72c4bccc..18abc58342f53 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3255,6 +3255,7 @@ class Serializer::DeclSerializer : public DeclVisitor { var->isGetterMutating(), var->isSetterMutating(), var->isLazyStorageProperty(), + var->isTopLevelGlobal(), S.addDeclRef(lazyStorage), accessors.OpaqueReadOwnership, accessors.ReadImpl, diff --git a/lib/SymbolGraphGen/Edge.cpp b/lib/SymbolGraphGen/Edge.cpp index 296cc0960fee2..22f43eacc5402 100644 --- a/lib/SymbolGraphGen/Edge.cpp +++ b/lib/SymbolGraphGen/Edge.cpp @@ -25,12 +25,14 @@ void Edge::serialize(llvm::json::OStream &OS) const { // In case a dependent module isn't available, serialize a fallback name. auto TargetModuleName = Target->getModuleContext()->getName().str(); + if (TargetModuleName != Walker->M.getName().str()) { - auto TargetSymbolIdentifier = Walker->getSymbolIdentifier(Target); - auto TargetComponents = TargetSymbolIdentifier.SimpleComponents; + SmallVector, 8> TargetPathComponents; + Walker->getPathComponents(Target, TargetPathComponents); + SmallString<128> Scratch(TargetModuleName); - for (auto it = TargetComponents.begin(); - it != TargetComponents.end(); ++it) { + for (auto it = TargetPathComponents.begin(); + it != TargetPathComponents.end(); ++it) { Scratch.push_back('.'); Scratch.append(*it); } diff --git a/lib/SymbolGraphGen/Symbol.cpp b/lib/SymbolGraphGen/Symbol.cpp index c30210d75a1e1..425b98217b921 100644 --- a/lib/SymbolGraphGen/Symbol.cpp +++ b/lib/SymbolGraphGen/Symbol.cpp @@ -76,15 +76,30 @@ void Symbol::serializeKind(llvm::json::OStream &OS) const { void Symbol::serializeIdentifier(SymbolGraphASTWalker &Walker, llvm::json::OStream &OS) const { - AttributeRAII A("identifier", OS); - Walker.getSymbolIdentifier(VD).serialize(OS); + OS.attributeObject("identifier", [&](){ + OS.attribute("precise", Walker.getUSR(VD)); + OS.attribute("interfaceLanguage", "swift"); + }); +} + +void Symbol::serializePathComponents(SymbolGraphASTWalker &Walker, + llvm::json::OStream &OS) const { + OS.attributeArray("pathComponents", [&](){ + SmallVector, 8> PathComponents; + Walker.getPathComponents(VD, PathComponents); + for (auto Component : PathComponents) { + OS.value(Component); + } + }); } void Symbol::serializeNames(SymbolGraphASTWalker &Walker, llvm::json::OStream &OS) const { OS.attributeObject("names", [&](){ - auto Identifier = Walker.getSymbolIdentifier(VD); - OS.attribute("title", Identifier.SimpleComponents.back()); + SmallVector, 8> PathComponents; + Walker.getPathComponents(VD, PathComponents); + + OS.attribute("title", PathComponents.back()); // "navigator": null Walker.serializeSubheadingDeclarationFragments("subheading", VD, OS); // "prose": null @@ -370,6 +385,7 @@ void Symbol::serialize(SymbolGraphASTWalker &Walker, OS.object([&](){ serializeKind(OS); serializeIdentifier(Walker, OS); + serializePathComponents(Walker, OS); serializeNames(Walker, OS); serializeDocComment(Walker, OS); diff --git a/lib/SymbolGraphGen/Symbol.h b/lib/SymbolGraphGen/Symbol.h index 9cdbca5757164..6e22255596b50 100644 --- a/lib/SymbolGraphGen/Symbol.h +++ b/lib/SymbolGraphGen/Symbol.h @@ -24,46 +24,6 @@ namespace symbolgraphgen { struct AvailabilityDomain; struct SymbolGraphASTWalker; -/** - An identifier for a symbol that provides a globally unique identifier suitable for - internal lookups and a locally unique path for human use, such as a URL. - */ -struct SymbolIdentifier { - /** - A string that uniquely identifies a symbol within a module in the event of - ambiguities. A precise identifier need not be human readable. - */ - StringRef PreciseIdentifier; - - /** - The components for a "fully qualified" identifier. - */ - ArrayRef SimpleComponents; - - SymbolIdentifier(llvm::StringRef PreciseIdentifier, - ArrayRef SimpleComponents) - : PreciseIdentifier(PreciseIdentifier), - SimpleComponents(SimpleComponents) { - assert(!PreciseIdentifier.empty()); - } - - void serialize(llvm::json::OStream &OS) const { - OS.object([&](){ - OS.attribute("precise", PreciseIdentifier); - OS.attributeArray("simpleComponents", [&](){ - for (auto Component : SimpleComponents) { - OS.value(Component); - } - }); - }); - } - - bool operator==(const SymbolIdentifier &Other) const { - return PreciseIdentifier == Other.PreciseIdentifier && - SimpleComponents == Other.SimpleComponents; - } -}; - /// A symbol from a module: a node in a graph. struct Symbol { const ValueDecl *VD; @@ -76,6 +36,9 @@ struct Symbol { void serializeIdentifier(SymbolGraphASTWalker &Walker, llvm::json::OStream &OS) const; + void serializePathComponents(SymbolGraphASTWalker &Walker, + llvm::json::OStream &OS) const; + void serializeNames(SymbolGraphASTWalker &Walker, llvm::json::OStream &OS) const; diff --git a/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp b/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp index 2ce1337d65468..cc370438be29b 100644 --- a/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp +++ b/lib/SymbolGraphGen/SymbolGraphASTWalker.cpp @@ -149,24 +149,15 @@ StringRef SymbolGraphASTWalker::getUSR(const ValueDecl *VD) { return USR; } -SymbolIdentifier -SymbolGraphASTWalker::getSymbolIdentifier(const ValueDecl *VD) { - // Look in the symbol identifier cache for this declartion. - auto Found = SymbolIdentifierCache.find(VD); - if (Found != SymbolIdentifierCache.end()) { - return Found->getSecond(); - } - - // Not found; need to build a symbol identifier and add it to the cache. - auto PreciseIdentifier = getUSR(VD); - llvm::SmallVector SimpleIdentifierChain; - +void +SymbolGraphASTWalker::getPathComponents(const ValueDecl *VD, + SmallVectorImpl> &Components) { // Collect the spellings of the fully qualified identifier components. auto Decl = VD; while (Decl && !isa(Decl)) { SmallString<32> Scratch; Decl->getFullName().getString(Scratch); - SimpleIdentifierChain.push_back(Ctx.allocateCopy(Scratch.str())); + Components.push_back(Scratch); if (const auto *DC = Decl->getDeclContext()) { if (const auto *Proto = DC->getExtendedProtocolDecl()) { Decl = Proto; @@ -179,17 +170,9 @@ SymbolGraphASTWalker::getSymbolIdentifier(const ValueDecl *VD) { Decl = nullptr; } } - - // The list is leaf-to-root, but our list is root-to-leaf, so reverse it. - std::reverse(SimpleIdentifierChain.begin(), SimpleIdentifierChain.end()); - SymbolIdentifier Identifier { - PreciseIdentifier, - Ctx.allocateCopy(llvm::makeArrayRef(SimpleIdentifierChain)) - }; - - SymbolIdentifierCache.insert({VD, Identifier}); - return Identifier; + // The list is leaf-to-root, but our list is root-to-leaf, so reverse it. + std::reverse(Components.begin(), Components.end()); } PrintOptions SymbolGraphASTWalker::getDeclarationFragmentsPrintOptions() const { diff --git a/lib/SymbolGraphGen/SymbolGraphASTWalker.h b/lib/SymbolGraphGen/SymbolGraphASTWalker.h index fb3e3dc9b6d0d..adf15ec5d46ca 100644 --- a/lib/SymbolGraphGen/SymbolGraphASTWalker.h +++ b/lib/SymbolGraphGen/SymbolGraphASTWalker.h @@ -27,7 +27,6 @@ class ValueDecl; namespace symbolgraphgen { -struct SymbolIdentifier; struct SymbolGraph; struct SymbolGraphOptions; @@ -49,9 +48,6 @@ struct SymbolGraphASTWalker : public SourceEntityWalker { /// A context for allocations. markup::MarkupContext Ctx; - /// A cache of identifiers for declarations that may be seen more than once. - llvm::DenseMap SymbolIdentifierCache; - /// A cache of USRs for declarations. llvm::DenseMap USRCache; @@ -72,8 +68,8 @@ struct SymbolGraphASTWalker : public SourceEntityWalker { /// Get the USR of a declaration and add it to the local allocator. StringRef getUSR(const ValueDecl *VD); - /// Returns a `SymbolIdentifier` for a given declaration. - SymbolIdentifier getSymbolIdentifier(const ValueDecl *VD); + /// Returns an array of path components for a declaration. + void getPathComponents(const ValueDecl *VD, SmallVectorImpl> &Components); // MARK: - Declaration Fragments diff --git a/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift b/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift index 002aef8e74145..bc849536a9429 100644 --- a/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift +++ b/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift @@ -162,10 +162,7 @@ public class _stdlib_Barrier { } deinit { - let ret = _stdlib_thread_barrier_destroy(_threadBarrierPtr) - if ret != 0 { - fatalError("_stdlib_thread_barrier_destroy() failed") - } + _stdlib_thread_barrier_destroy(_threadBarrierPtr) } public func wait() { diff --git a/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift b/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift index 9f5e183447021..54517a901b117 100644 --- a/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift +++ b/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift @@ -69,13 +69,12 @@ public func _stdlib_thread_barrier_init( InitializeConditionVariable(barrier.pointee.cond!) #else barrier.pointee.mutex = UnsafeMutablePointer.allocate(capacity: 1) - if pthread_mutex_init(barrier.pointee.mutex!, nil) != 0 { - // FIXME: leaking memory. - return -1 - } barrier.pointee.cond = UnsafeMutablePointer.allocate(capacity: 1) - if pthread_cond_init(barrier.pointee.cond!, nil) != 0 { - // FIXME: leaking memory, leaking a mutex. + guard _stdlib_thread_barrier_mutex_and_cond_init(barrier) == 0 else { + barrier.pointee.mutex!.deinitialize(count: 1) + barrier.pointee.mutex!.deallocate() + barrier.pointee.cond!.deinitialize(count: 1) + barrier.pointee.cond!.deallocate() return -1 } #endif @@ -83,20 +82,29 @@ public func _stdlib_thread_barrier_init( return 0 } +#if !os(Windows) +private func _stdlib_thread_barrier_mutex_and_cond_init(_ barrier: UnsafeMutablePointer<_stdlib_thread_barrier_t>) -> CInt { + guard pthread_mutex_init(barrier.pointee.mutex!, nil) == 0 else { + return -1 + } + guard pthread_cond_init(barrier.pointee.cond!, nil) == 0 else { + pthread_mutex_destroy(barrier.pointee.mutex!) + return -1 + } + return 0 +} +#endif + public func _stdlib_thread_barrier_destroy( _ barrier: UnsafeMutablePointer<_stdlib_thread_barrier_t> -) -> CInt { +) { #if os(Windows) // Condition Variables do not need to be explicitly destroyed // Mutexes do not need to be explicitly destroyed #else - if pthread_cond_destroy(barrier.pointee.cond!) != 0 { - // FIXME: leaking memory, leaking a mutex. - return -1 - } - if pthread_mutex_destroy(barrier.pointee.mutex!) != 0 { - // FIXME: leaking memory. - return -1 + guard pthread_cond_destroy(barrier.pointee.cond!) == 0 && + pthread_mutex_destroy(barrier.pointee.mutex!) == 0 else { + fatalError("_stdlib_thread_barrier_destroy() failed") } #endif barrier.pointee.cond!.deinitialize(count: 1) @@ -105,7 +113,7 @@ public func _stdlib_thread_barrier_destroy( barrier.pointee.mutex!.deinitialize(count: 1) barrier.pointee.mutex!.deallocate() - return 0 + return } public func _stdlib_thread_barrier_wait( diff --git a/test/APINotes/versioned-objc.swift b/test/APINotes/versioned-objc.swift index b2b5cc76ea6c9..9f9b2b64611cd 100644 --- a/test/APINotes/versioned-objc.swift +++ b/test/APINotes/versioned-objc.swift @@ -166,7 +166,7 @@ extension PrintingInterference { func testDroppingRenamedPrints() { // CHECK-DIAGS-4: [[@LINE+1]]:{{[0-9]+}}: warning: use of 'print' treated as a reference to instance method print(self) - // CHECK-DIAGS-5: [[@LINE-1]]:{{[0-9]+}}: error: missing argument for parameter 'extra' in call + // CHECK-DIAGS-5: [[@LINE-1]]:{{[0-9]+}}: error: use of 'print' refers to instance method rather than global function 'print(_:separator:terminator:)' in module 'Swift' // CHECK-DIAGS-4-NOT: [[@LINE+1]]:{{[0-9]+}}: print(self, extra: self) diff --git a/test/ClangImporter/Inputs/frameworks/CategoryOverrides.framework/Headers/CategoryOverrides.h b/test/ClangImporter/Inputs/frameworks/CategoryOverrides.framework/Headers/CategoryOverrides.h index 03c13252ac497..4c66878d60f8a 100644 --- a/test/ClangImporter/Inputs/frameworks/CategoryOverrides.framework/Headers/CategoryOverrides.h +++ b/test/ClangImporter/Inputs/frameworks/CategoryOverrides.framework/Headers/CategoryOverrides.h @@ -19,3 +19,16 @@ typedef struct SomeStruct_s { @interface MyDerivedClass : MyBaseClass @property (nonatomic, strong, nullable) Base *derivedMember; @end + +typedef enum { + Caster, + Grantulated, + Confectioners, + Cane, + Demerara, + Turbinado, +} RefinedSugar /*NS_REFINED_FOR_SWIFT*/ __attribute__((swift_private)); + +@interface Refinery : Base +@property (nonatomic, readonly) RefinedSugar sugar /*NS_REFINED_FOR_SWIFT*/ __attribute__((swift_private)); +@end diff --git a/test/ClangImporter/Inputs/frameworks/CategoryOverrides.framework/PrivateHeaders/Private.h b/test/ClangImporter/Inputs/frameworks/CategoryOverrides.framework/PrivateHeaders/Private.h index d52dd6c550ec9..0c4ed45702bca 100644 --- a/test/ClangImporter/Inputs/frameworks/CategoryOverrides.framework/PrivateHeaders/Private.h +++ b/test/ClangImporter/Inputs/frameworks/CategoryOverrides.framework/PrivateHeaders/Private.h @@ -14,3 +14,7 @@ @interface MyBaseClass () @end + +@interface Refinery () +@property (nonatomic, readwrite) RefinedSugar sugar; +@end diff --git a/test/ClangImporter/attr-swift_private.swift b/test/ClangImporter/attr-swift_private.swift index 05ddc81835f30..f249454b15d96 100644 --- a/test/ClangImporter/attr-swift_private.swift +++ b/test/ClangImporter/attr-swift_private.swift @@ -121,7 +121,7 @@ func testCF(_ a: __PrivCFType, b: __PrivCFSub, c: __PrivInt) { makeSureAnyObject(a) makeSureAnyObject(b) #if !IRGEN - makeSureAnyObject(c) // expected-error {{argument type '__PrivInt' (aka 'Int32') does not conform to expected type 'AnyObject'}} + makeSureAnyObject(c) // expected-error {{argument type '__PrivInt' (aka 'Int32') expected to be an instance of a class or class-constrained type}} #endif } diff --git a/test/ClangImporter/objc_redeclared_properties_categories.swift b/test/ClangImporter/objc_redeclared_properties_categories.swift index 0281251b87a75..7cf1ae534e37b 100644 --- a/test/ClangImporter/objc_redeclared_properties_categories.swift +++ b/test/ClangImporter/objc_redeclared_properties_categories.swift @@ -1,11 +1,11 @@ // RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck -F %S/Inputs/frameworks %s 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-PUBLIC %s // RUN: echo '#import ' > %t.h -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.h %s 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s --allow-empty +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.h %s 2>&1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s --allow-empty // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -emit-pch -F %S/Inputs/frameworks -o %t.pch %t.h -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.pch %s 2>&1 | %FileCheck --allow-empty -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.h -pch-output-dir %t/pch %s 2>&1 | %FileCheck --allow-empty -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.pch %s 2>&1 | %FileCheck --allow-empty -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks -enable-objc-interop -import-objc-header %t.h -pch-output-dir %t/pch %s 2>&1 | %FileCheck --allow-empty -check-prefix=CHECK -check-prefix=CHECK-PRIVATE %s import CategoryOverrides @@ -54,3 +54,27 @@ func takesABaseClass(_ x: MyBaseClass) { // CHECK-PRIVATE-NOT: has no member 'derivedMember' x.derivedMember = Base() } + +// A category declared in a (private) header can introduce overrides of a +// property that has mismatched Swift naming conventions. If we see a +// non-__attribute__((swift_private)) decl, sometimes it comes in too. + +extension Refinery { + public enum RefinedSugar { + case caster + case grantulated + case confectioners + case cane + case demerara + case turbinado + } + + public var sugar: Refinery.RefinedSugar { + return .caster // RefinedSugar(self.__sugar) + } +} + +func takesARefinery(_ x: Refinery) { + // CHECK: cannot assign to property: 'sugar' is a get-only property + x.sugar = .caster +} diff --git a/test/Constraints/bridging.swift b/test/Constraints/bridging.swift index 4cdc52e3e2626..c40fb0bdf181d 100644 --- a/test/Constraints/bridging.swift +++ b/test/Constraints/bridging.swift @@ -89,7 +89,7 @@ func bridgeToObjC(_ s: BridgedStruct) -> BridgedClass { } func bridgeToAnyObject(_ s: BridgedStruct) -> AnyObject { - return s // expected-error{{return expression of type 'BridgedStruct' does not conform to 'AnyObject'}} + return s // expected-error{{return expression of type 'BridgedStruct' expected to be an instance of a class or class-constrained type}} return s as AnyObject } @@ -344,14 +344,14 @@ func forceUniversalBridgeToAnyObject(a: T, b: U, c: An z = g as AnyObject z = h as AnyObject - z = a // expected-error{{does not conform to 'AnyObject'}} + z = a // expected-error{{value of type 'T' expected to be an instance of a class or class-constrained type in assignment}} z = b - z = c // expected-error{{does not conform to 'AnyObject'}} expected-note {{cast 'Any' to 'AnyObject'}} {{8-8= as AnyObject}} - z = d // expected-error{{does not conform to 'AnyObject'}} + z = c // expected-error{{value of type 'Any' expected to be an instance of a class or class-constrained type in assignment}} expected-note {{cast 'Any' to 'AnyObject'}} {{8-8= as AnyObject}} + z = d // expected-error{{value of type 'KnownUnbridged' expected to be an instance of a class or class-constrained type in assignment}} z = e z = f z = g - z = h // expected-error{{does not conform to 'AnyObject'}} + z = h // expected-error{{value of type 'String' expected to be an instance of a class or class-constrained type in assignment}} _ = z } diff --git a/test/Constraints/conditionally_defined_types.swift b/test/Constraints/conditionally_defined_types.swift index 2107fa6e6faca..193d40a7f766d 100644 --- a/test/Constraints/conditionally_defined_types.swift +++ b/test/Constraints/conditionally_defined_types.swift @@ -222,3 +222,15 @@ let _ = Conforms.Decl4.Decl2.self // expected-error {{type 'Z2.T' (aka 'Y let _ = Conforms.Decl4.Decl3.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} let _ = Conforms.Decl4.Decl4.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} let _ = Conforms.Decl4.Decl5.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} + +// rdar://problem/45271663 +protocol PP { associatedtype V } +struct SS {} +enum EE {} +extension EE : PP where A : PP, B : PP { typealias V = EE } + +protocol P2 { associatedtype U } +func f(s: SS) -> SS> where PI.U : PP, PI.V : P2 { + let t: EE.V + // expected-error@-1 {{type 'PI.V.U' does not conform to protocol 'PP'}} +} diff --git a/test/Constraints/enum_cases.swift b/test/Constraints/enum_cases.swift index 5a918dacd6fa1..dbfe34ec5ca59 100644 --- a/test/Constraints/enum_cases.swift +++ b/test/Constraints/enum_cases.swift @@ -22,14 +22,14 @@ let _ = arr.map(E.bar) // Ok let _ = arr.map(E.two) // expected-error {{cannot invoke 'map' with an argument list of type '(@escaping (Int, Int) -> E)'}} // expected-note@-1{{expected an argument list of type '((Self.Element) throws -> T)'}} -let _ = arr.map(E.tuple) // expected-error {{cannot invoke 'map' with an argument list of type '(@escaping ((x: Int, y: Int)) -> E)'}} -// expected-note@-1{{expected an argument list of type '((Self.Element) throws -> T)'}} +let _ = arr.map(E.tuple) // expected-error {{cannot convert value of type '((x: Int, y: Int)) -> E' to expected argument type '(String) throws -> T'}} +// expected-error@-1 {{generic parameter 'T' could not be inferred}} let _ = arr.map(G_E.foo) // Ok let _ = arr.map(G_E.bar) // Ok let _ = arr.map(G_E.two) // expected-error {{cannot convert value of type '(String, String) -> G_E' to expected argument type '(String) throws -> G_E'}} -let _ = arr.map(G_E.tuple) // expected-error {{cannot invoke 'map' with an argument list of type '(@escaping ((x: Int, y: Int)) -> G_E)'}} -// expected-note@-1{{expected an argument list of type '((Self.Element) throws -> T)'}} +let _ = arr.map(G_E.tuple) // expected-error {{cannot convert value of type '((x: Int, y: Int)) -> G_E' to expected argument type '(String) throws -> T'}} +// expected-error@-1 {{generic parameter 'T' could not be inferred}} let _ = E.foo("hello") // expected-error {{missing argument label 'bar:' in call}} let _ = E.bar("hello") // Ok diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index c2de930b8b443..1720948609d3c 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -355,7 +355,7 @@ do { // rdar://problem/25341015 extension Sequence { func r25341015_1() -> Int { - return max(1, 2) // expected-error {{use of 'max' refers to instance method 'max(by:)' rather than global function 'max' in module 'Swift'}} expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} + return max(1, 2) // expected-error {{use of 'max' refers to instance method rather than global function 'max' in module 'Swift'}} expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} } } @@ -381,7 +381,7 @@ func r25341015() { class Bar { func baz() {} func qux() { - baz(1, 2) // expected-error {{argument passed to call that takes no arguments}} + baz(1, 2) // expected-error {{use of 'baz' refers to instance method rather than local function 'baz'}} } } } @@ -405,17 +405,17 @@ func bar_32854314() -> Int { extension Array where Element == Int { func foo() { let _ = min(foo_32854314(), bar_32854314()) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}} - // expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min(by:)'}} + // expected-error@-1 {{use of 'min' refers to instance method rather than global function 'min' in module 'Swift'}} } func foo(_ x: Int, _ y: Double) { let _ = min(x, y) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}} - // expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min(by:)'}} + // expected-error@-1 {{use of 'min' refers to instance method rather than global function 'min' in module 'Swift'}} } func bar() { let _ = min(1.0, 2) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}} - // expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min(by:)'}} + // expected-error@-1 {{use of 'min' refers to instance method rather than global function 'min' in module 'Swift'}} } } diff --git a/test/Constraints/tuple_arguments.swift b/test/Constraints/tuple_arguments.swift index 3011132d48d78..0b1852ea221ed 100644 --- a/test/Constraints/tuple_arguments.swift +++ b/test/Constraints/tuple_arguments.swift @@ -1702,7 +1702,8 @@ _ = x.map { (_: ()) in () } // https://bugs.swift.org/browse/SR-9470 do { func f(_: Int...) {} - let _ = [(1, 2, 3)].map(f) // expected-error {{cannot invoke 'map' with an argument list of type '(@escaping (Int...) -> ())'}} + let _ = [(1, 2, 3)].map(f) // expected-error {{cannot convert value of type '(Int...) -> ()' to expected argument type '((Int, Int, Int)) throws -> T'}} + // expected-error@-1 {{generic parameter 'T' could not be inferred}} } // rdar://problem/48443263 - cannot convert value of type '() -> Void' to expected argument type '(_) -> Void' diff --git a/test/DebugInfo/inlinescopes.swift b/test/DebugInfo/inlinescopes.swift index 769b8a38ce8f0..6c4a3a4fefc3d 100644 --- a/test/DebugInfo/inlinescopes.swift +++ b/test/DebugInfo/inlinescopes.swift @@ -6,7 +6,7 @@ // RUN: %FileCheck %s -check-prefix=TRANSPARENT-CHECK < %t.ll // CHECK: define{{( dllexport)?}}{{( protected)?( signext)?}} i32 @main{{.*}} -// CHECK: call swiftcc i64 @"$s4main8noinlineys5Int64VADF"(i64 %4), !dbg ![[CALL:.*]] +// CHECK: call swiftcc i64 @"$s4main8noinlineys5Int64VADF"(i64 %{{.*}}), !dbg ![[CALL:.*]] // CHECK-DAG: ![[TOPLEVEL:.*]] = !DIFile(filename: "{{.*}}inlinescopes.swift" import FooBar diff --git a/test/Frontend/type-fingerprint.swift b/test/Frontend/type-fingerprint.swift index 8d9188e8362c4..aa08da31bedf2 100644 --- a/test/Frontend/type-fingerprint.swift +++ b/test/Frontend/type-fingerprint.swift @@ -12,16 +12,27 @@ // RUN: cp %S/Inputs/type-fingerprint/{main,a}.swift %t // RUN: cp %S/Inputs/type-fingerprint/ofm.json %t // RUN: cp %S/Inputs/type-fingerprint/b0.swift %t/b.swift + +// Seeing weird failure on CI, so set the mod times +// RUN: touch -t 200101010101 %t/*.swift + // RUN: cd %t && %swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental ./main.swift ./a.swift ./b.swift -module-name main -output-file-map ofm.json >&output1 -// RUN: cp %t/b.swiftdeps %t/b1.swiftdeps +// only-run-for-debugging: cp %t/b.swiftdeps %t/b1.swiftdeps // Change one type, but uses of all types get recompiled // RUN: cp %S/Inputs/type-fingerprint/b1.swift %t/b.swift + +// Seeing weird failure on CI, so ensure that b.swift is newer +// RUN: touch -t 200201010101 %t/* +// RUN: touch -t 200101010101 %t/*.swift +// RUN: touch -t 200301010101 %t/b.swift + // RUN: cd %t && %swiftc_driver -disable-type-fingerprints -enable-batch-mode -j2 -incremental -driver-show-incremental ./main.swift ./a.swift ./b.swift -module-name main -output-file-map ofm.json >&output2 -// RUN: cp %t/b.swiftdeps %t/b2.swiftdeps +// Save for debugging: +// only-run-for-debugging: cp %t/b.swiftdeps %t/b2.swiftdeps // RUN: %FileCheck -check-prefix=CHECK-MAINAB-RECOMPILED %s < %t/output2 @@ -40,16 +51,26 @@ // RUN: cp %S/Inputs/type-fingerprint/{main,a}.swift %t // RUN: cp %S/Inputs/type-fingerprint/ofm.json %t // RUN: cp %S/Inputs/type-fingerprint/b0.swift %t/b.swift + +// Seeing weird failure on CI, so set the mod times +// RUN: touch -t 200101010101 %t/*.swift + // RUN: cd %t && %swiftc_driver -enable-batch-mode -j2 -incremental -driver-show-incremental ./main.swift ./a.swift ./b.swift -module-name main -output-file-map ofm.json >&output3 -// RUN: cp %t/b.swiftdeps %t/b3.swiftdeps +// only-run-for-debugging: cp %t/b.swiftdeps %t/b3.swiftdeps // Change one type, only uses of that type get recompiled // RUN: cp %S/Inputs/type-fingerprint/b1.swift %t/b.swift + +// Seeing weird failure on CI, so ensure that b.swift is newer +// RUN: touch -t 200201010101 %t/* +// RUN: touch -t 200101010101 %t/*.swift +// RUN: touch -t 200301010101 %t/b.swift + // RUN: cd %t && %swiftc_driver -enable-batch-mode -j2 -incremental -driver-show-incremental ./main.swift ./a.swift ./b.swift -module-name main -output-file-map ofm.json >&output4 -// RUN: cp %t/b.swiftdeps %t/b4.swiftdeps +// only-run-for-debugging: cp %t/b.swiftdeps %t/b4.swiftdeps // RUN: %FileCheck -check-prefix=CHECK-MAINB-RECOMPILED %s < %t/output4 diff --git a/test/Generics/existential_restrictions.swift b/test/Generics/existential_restrictions.swift index ae652220daa2b..fbf2f29375fc5 100644 --- a/test/Generics/existential_restrictions.swift +++ b/test/Generics/existential_restrictions.swift @@ -25,7 +25,7 @@ func fT(_ t: T) { } func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) { fP(p) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} fAO(p) // expected-error{{global function 'fAO' requires that 'P' be a class type}} - fAOE(p) // expected-error{{argument type 'P' does not conform to expected type 'AnyObject'}} + fAOE(p) // expected-error{{argument type 'P' expected to be an instance of a class or class-constrained type}} fT(p) fOP(op) diff --git a/test/Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh b/test/Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh new file mode 100755 index 0000000000000..80bb392c22cfb --- /dev/null +++ b/test/Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh +# Fine-grained swiftdeps files use multiple lines for each graph node. +# Compress such a file so that each entry is one line of the form: +# +# Also sort for consistency, since the node order can vary. + +awk '/kind:/ {k = $2; f = ""}; /aspect:/ {a = $2}; /context:/ {c = $2}; /name/ {n = $2}; /sequenceNumber/ {s = $2}; /fingerprint:/ {f = $2 }; /isProvides:/ {isP = $2; print k, a, c, n, isP, f}' | sort diff --git a/test/InterfaceHash/added_method-type-fingerprints.swift b/test/InterfaceHash/added_method-type-fingerprints.swift new file mode 100644 index 0000000000000..7b51e1f67b758 --- /dev/null +++ b/test/InterfaceHash/added_method-type-fingerprints.swift @@ -0,0 +1,55 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +class C { + func f2() -> Int { + return 0 + } +} + +// BEGIN b.swift +class C { + func f2() -> Int { + return 0 + } + + func f3() -> Int { + return 1 + } +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_class_private_property-type-fingerprints.swift b/test/InterfaceHash/added_private_class_private_property-type-fingerprints.swift new file mode 100644 index 0000000000000..cf3a104cc71b1 --- /dev/null +++ b/test/InterfaceHash/added_private_class_private_property-type-fingerprints.swift @@ -0,0 +1,53 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +private class C { + func f2() -> Int { + return 0 + } +} + +// BEGIN b.swift +private class C { + func f2() -> Int { + return 0 + } + + private var x: Int = 0 +} + +// Since C is a type or extension, the interface hash ought to not get the +// changed token hash. + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_class_property-type-fingerprints.swift b/test/InterfaceHash/added_private_class_property-type-fingerprints.swift new file mode 100644 index 0000000000000..f4e01619c1b76 --- /dev/null +++ b/test/InterfaceHash/added_private_class_property-type-fingerprints.swift @@ -0,0 +1,53 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +class C { + func f2() -> Int { + return 0 + } +} + +// BEGIN b.swift +class C { + func f2() -> Int { + return 0 + } + + private var x: Int = 0 +} + +// Since C is a type or extension, the interface hash ought to not get the +// changed token hash. + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_enum_private_property-type-fingerprints.swift b/test/InterfaceHash/added_private_enum_private_property-type-fingerprints.swift new file mode 100644 index 0000000000000..9ad0b28d56449 --- /dev/null +++ b/test/InterfaceHash/added_private_enum_private_property-type-fingerprints.swift @@ -0,0 +1,56 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + + +// BEGIN a.swift +private enum A { + case x, y + func f2() -> Int { + return 0 + } +} + +// BEGIN b.swift +private enum A { + case x, y + func f2() -> Int { + return 0 + } + + var foo: Int { return 0 } +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_enum_property-type-fingerprints.swift b/test/InterfaceHash/added_private_enum_property-type-fingerprints.swift new file mode 100644 index 0000000000000..c8220f6f9a54b --- /dev/null +++ b/test/InterfaceHash/added_private_enum_property-type-fingerprints.swift @@ -0,0 +1,55 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +enum A { + case x, y + func f2() -> Int { + return 0 + } +} + +// BEGIN b.swift +enum A { + case x, y + func f2() -> Int { + return 0 + } + + private var foo: Int { return 0 } +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_method-type-fingerprints.swift b/test/InterfaceHash/added_private_method-type-fingerprints.swift new file mode 100644 index 0000000000000..c0c60206d9c92 --- /dev/null +++ b/test/InterfaceHash/added_private_method-type-fingerprints.swift @@ -0,0 +1,55 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +class C { + func f2() -> Int { + return 0 + } +} + +// BEGIN b.swift +class C { + func f2() -> Int { + return 0 + } + + private func f3() -> Int { + return 1 + } +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' C true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' C true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1C{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1C{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1C{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_method_value_types-type-fingerprints.swift b/test/InterfaceHash/added_private_method_value_types-type-fingerprints.swift new file mode 100644 index 0000000000000..42fee00e31bf0 --- /dev/null +++ b/test/InterfaceHash/added_private_method_value_types-type-fingerprints.swift @@ -0,0 +1,88 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +struct A { + func f2() -> Int { + return 0 + } +} + +enum B { + case x, y + func f2() -> Int { + return 0 + } +} + +// BEGIN b.swift +struct A { + func f2() -> Int { + return 0 + } + + private func f3() -> Int { + return 1 + } +} + +enum B { + case x, y + func f2() -> Int { + return 0 + } + + private func f3() -> Int { + return 1 + } +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' A true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' A true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1A{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1A{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1A{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' B true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' B true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' B true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' B true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1B{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1B{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1B{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_protocol_method-type-fingerprints.swift b/test/InterfaceHash/added_private_protocol_method-type-fingerprints.swift new file mode 100644 index 0000000000000..c0ccd54a11771 --- /dev/null +++ b/test/InterfaceHash/added_private_protocol_method-type-fingerprints.swift @@ -0,0 +1,50 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +private protocol P { + func f2() -> Int + var y: Int { get set } +} + +// BEGIN b.swift +private protocol P { + func f2() -> Int + func f3() -> Int + var y: Int { get set } +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' P true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1P{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1P{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_protocol_property-type-fingerprints.swift b/test/InterfaceHash/added_private_protocol_property-type-fingerprints.swift new file mode 100644 index 0000000000000..c27cee3752b83 --- /dev/null +++ b/test/InterfaceHash/added_private_protocol_property-type-fingerprints.swift @@ -0,0 +1,50 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +private protocol P { + func f2() -> Int + var y: Int { get set } +} + +// BEGIN b.swift +private protocol P { + func f2() -> Int + var x: Int { get set } + var y: Int { get set } +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' P true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' P true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1P{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1P{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1P{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_struct_private_property-type-fingerprints.swift b/test/InterfaceHash/added_private_struct_private_property-type-fingerprints.swift new file mode 100644 index 0000000000000..47e371aff0901 --- /dev/null +++ b/test/InterfaceHash/added_private_struct_private_property-type-fingerprints.swift @@ -0,0 +1,56 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +struct S { + func f2() -> Int { + return 0 + } + + var y: Int = 0 +} + +// BEGIN b.swift +struct S { + func f2() -> Int { + return 0 + } + + private var x: Int = 0 + var y: Int = 0 +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' S true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1S{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1S{{[^ ]+}} '' true diff --git a/test/InterfaceHash/added_private_struct_property-type-fingerprints.swift b/test/InterfaceHash/added_private_struct_property-type-fingerprints.swift new file mode 100644 index 0000000000000..bd92b5dfbe37f --- /dev/null +++ b/test/InterfaceHash/added_private_struct_property-type-fingerprints.swift @@ -0,0 +1,56 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: not diff %t/{a,b}-processed.swiftdeps >%t/diffs + +// BEGIN a.swift +private struct S { + func f2() -> Int { + return 0 + } + + var y: Int = 0 +} + +// BEGIN b.swift +private struct S { + func f2() -> Int { + return 0 + } + + var x: Int = 0 + var y: Int = 0 +} + +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-SAME-INTERFACE-HASH +// RUN: %FileCheck %s <%t/diffs -check-prefix=CHECK-DIFFERENT-TYPE-FINGERPRINT + +// CHECK-SAME-INTERFACE-HASH-NOT: sourceFileProvides + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel implementation '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < topLevel interface '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel implementation '' S true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > topLevel interface '' S true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < nominal interface 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > nominal interface 4main1S{{[^ ]+}} '' true + +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: < potentialMember interface 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember implementation 4main1S{{[^ ]+}} '' true +// CHECK-DIFFERENT-TYPE-FINGERPRINT-DAG: > potentialMember interface 4main1S{{[^ ]+}} '' true diff --git a/test/InterfaceHash/edited_method_body-type-fingerprints.swift b/test/InterfaceHash/edited_method_body-type-fingerprints.swift new file mode 100644 index 0000000000000..10ae3e000c09f --- /dev/null +++ b/test/InterfaceHash/edited_method_body-type-fingerprints.swift @@ -0,0 +1,31 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: cmp %t/{a,b}-processed.swiftdeps + +// BEGIN a.swift +class C { + func f2() -> Int { + return 0 + } +} + +// BEGIN b.swift +class C { + func f2() -> Int { + return 1 + } +} diff --git a/test/InterfaceHash/edited_method_body.swift b/test/InterfaceHash/edited_method_body.swift index 2f87dd9f02fef..b0aebce44e500 100644 --- a/test/InterfaceHash/edited_method_body.swift +++ b/test/InterfaceHash/edited_method_body.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash +// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash +// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash // RUN: cmp %t/a.hash %t/b.hash // BEGIN a.swift diff --git a/test/InterfaceHash/edited_property_getter-type-fingerprints.swift b/test/InterfaceHash/edited_property_getter-type-fingerprints.swift new file mode 100644 index 0000000000000..0a0b5fdaaff54 --- /dev/null +++ b/test/InterfaceHash/edited_property_getter-type-fingerprints.swift @@ -0,0 +1,33 @@ +// REQUIRES: shell +// Also uses awk: +// XFAIL OS=windows + +// When adding a private protocol method, the interface hash should stay the same +// The per-type fingerprint should change + +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s +// RUN: cp %t/{a,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/a-processed.swiftdeps +// RUN: cp %t/{b,x}.swift +// RUN: %target-swift-frontend -typecheck -enable-type-fingerprints -primary-file %t/x.swift -emit-reference-dependencies-path %t/x.swiftdeps -module-name main +// RUN: %S/../Inputs/process_fine_grained_swiftdeps_with_fingerprints.sh <%t/x.swiftdeps >%t/b-processed.swiftdeps + +// RUN: cmp %t/{a,b}-processed.swiftdeps + +// BEGIN a.swift +class C { + var p: Int { + return 0 + } +} + +// BEGIN b.swift +class C { + var p: Int { + let x = 1 + return x + } +} + diff --git a/test/InterfaceHash/edited_property_getter.swift b/test/InterfaceHash/edited_property_getter.swift index 42584e33f6467..deaeb8ccc08dc 100644 --- a/test/InterfaceHash/edited_property_getter.swift +++ b/test/InterfaceHash/edited_property_getter.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %{python} %utils/split_file.py -o %t %s -// RUN: %target-swift-frontend -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash -// RUN: %target-swift-frontend -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash +// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/a.swift 2> %t/a.hash +// RUN: %target-swift-frontend -disable-type-fingerprints -dump-interface-hash -primary-file %t/b.swift 2> %t/b.hash // RUN: cmp %t/a.hash %t/b.hash // BEGIN a.swift diff --git a/test/Interpreter/SDK/misc_osx.swift b/test/Interpreter/SDK/misc_osx.swift index fabd2413023c3..15383cf784077 100644 --- a/test/Interpreter/SDK/misc_osx.swift +++ b/test/Interpreter/SDK/misc_osx.swift @@ -13,5 +13,5 @@ func testFSEventStreamRef(stream: FSEventStreamRef) { FSEventStreamRetain(stream) // no-warning FSEventStreamRelease(stream) - let _: AnyObject = stream // expected-error {{value of type 'FSEventStreamRef' (aka 'OpaquePointer') does not conform to specified type 'AnyObject'}} + let _: AnyObject = stream // expected-error {{value of type 'FSEventStreamRef' (aka 'OpaquePointer') expected to be instance of class or class-constrained type}} } diff --git a/test/ModuleInterface/inherited-generic-parameters.swift b/test/ModuleInterface/inherited-generic-parameters.swift index 4a538a33942b7..1be75a69d7311 100644 --- a/test/ModuleInterface/inherited-generic-parameters.swift +++ b/test/ModuleInterface/inherited-generic-parameters.swift @@ -15,6 +15,10 @@ public class Base { // CHECK-NEXT: public init(x: @escaping (In) -> Out) public init(x: @escaping (In) -> Out) {} + +// CHECK-NEXT: public init(_: A, _: A) + public init(_: A, _: A) {} + // CHECK: } } @@ -22,6 +26,7 @@ public class Base { public class Derived : Base { // CHECK-NEXT: {{(@objc )?}}deinit // CHECK-NEXT: override public init(x: @escaping (T) -> T) +// CHECK-NEXT: override public init(_ argument: A, _ argument: A) // CHECK-NEXT: } } diff --git a/test/NameBinding/name_lookup_min_max_conditional_conformance.swift b/test/NameBinding/name_lookup_min_max_conditional_conformance.swift index 81d2e59582cfa..e79212e6aa318 100644 --- a/test/NameBinding/name_lookup_min_max_conditional_conformance.swift +++ b/test/NameBinding/name_lookup_min_max_conditional_conformance.swift @@ -16,7 +16,7 @@ extension ContainsMinMax { func min() {} } -func foo(_: Int, _: Int) {} +func foo(_: Int, _: Int) {} // expected-note 2 {{'foo' declared here}} protocol ContainsFoo {} extension ContainsFoo { @@ -34,15 +34,14 @@ extension NonConditional { // expected-error@-1{{use of 'min' refers to instance method}} // expected-note@-2{{use 'Swift.' to reference the global function}} - // FIXME(diagnostics): Better diagnostic in this case would be to suggest to add `name_lookup_min_max_conditional_conformance.` - // to call because name `foo` is shadowed by instance method without arguments. Would be fixed by `resolveDeclRefExpr` refactoring. - _ = foo(5, 6) // expected-error {{argument passed to call that takes no arguments}} + _ = foo(5, 6) // expected-error {{use of 'foo' refers to instance method rather than global function 'foo' in module 'name_lookup_min_max_conditional_conformance'}} + // expected-note@-1 {{use 'name_lookup_min_max_conditional_conformance.' to reference the global function in module 'name_lookup_min_max_conditional_conformance'}} {{13-13=name_lookup_min_max_conditional_conformance.}} } } struct Conditional {} extension Conditional: ContainsMinMax where T: ContainsMinMax {} -extension Conditional: ContainsFoo where T: ContainsFoo {} // expected-note {{requirement from conditional conformance of 'Conditional' to 'ContainsFoo'}} +extension Conditional: ContainsFoo where T: ContainsFoo {} extension Conditional { func f() { @@ -53,9 +52,8 @@ extension Conditional { // expected-warning@-1{{use of 'min' as reference to global function in module 'Swift' will change in future versions of Swift to reference instance method in generic struct 'Conditional' which comes via a conditional conformance}} // expected-note@-2{{use 'Swift.' to continue to reference the global function}} - // FIXME(diagnostics): Same as line 39, there should be only one error here about shadowing. _ = foo(5, 6) - // expected-error@-1 {{referencing instance method 'foo()' on 'Conditional' requires that 'T' conform to 'ContainsFoo'}} - // expected-error@-2 {{argument passed to call that takes no arguments}} + // expected-error@-1 {{use of 'foo' refers to instance method rather than global function 'foo' in module 'name_lookup_min_max_conditional_conformance'}} + // expected-note@-2 {{use 'name_lookup_min_max_conditional_conformance.' to reference the global function in module 'name_lookup_min_max_conditional_conformance'}} {{13-13=name_lookup_min_max_conditional_conformance.}} } } diff --git a/test/NameBinding/reference-dependencies-fine.swift b/test/NameBinding/reference-dependencies-fine.swift index f9e4b38ab5f65..e15fbcf24e500 100644 --- a/test/NameBinding/reference-dependencies-fine.swift +++ b/test/NameBinding/reference-dependencies-fine.swift @@ -4,10 +4,11 @@ // RUN: %empty-directory(%t) // RUN: cp %s %t/main.swift -// RUN: %target-swift-frontend -enable-fine-grained-dependencies -typecheck -primary-file %t/main.swift %S/Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps +// Need -fine-grained-dependency-include-intrafile to be invarient wrt type-body-fingerprints enabled/disabled +// RUN: %target-swift-frontend -enable-fine-grained-dependencies -fine-grained-dependency-include-intrafile -typecheck -primary-file %t/main.swift %S/Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps // Check that the output is deterministic. -// RUN: %target-swift-frontend -enable-fine-grained-dependencies -typecheck -primary-file %t/main.swift %S/Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t-2.swiftdeps +// RUN: %target-swift-frontend -enable-fine-grained-dependencies -fine-grained-dependency-include-intrafile -typecheck -primary-file %t/main.swift %S/Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t-2.swiftdeps // Merge each entry onto one line and sort to overcome order differences // RUN: %S/../Inputs/process_fine_grained_swiftdeps.sh <%t.swiftdeps >%t-processed.swiftdeps @@ -339,7 +340,8 @@ struct Outer { } } -// CHECK-TOPLEVEL-DAG: topLevel interface '' privateFunc false +// CHECK-TOPLEVEL-DAG: topLevel interface '' privateFunc true +// CHECK-TOPLEVEL-DAG: topLevel implementation '' privateFunc true private func privateFunc() {} // CHECK-TOPLEVEL-DAG: topLevel interface '' topLevel1 false @@ -498,7 +500,8 @@ struct Sentinel2 {} // CHECK-POTENTIALMEMBER-DAG: potentialMember interface 4main13PrivateProto3P '' false // CHECK-NOMINAL-2-DAG: nominal interface Sa '' false -// CHECK-NOMINAL-2-DAG: nominal interface Sb '' false +// CHECK-NOMINAL-2-DAG: nominal interface Sb '' true +// CHECK-NOMINAL-2-DAG: nominal implementation Sb '' true // CHECK-NOMINAL-2-DAG: nominal interface 4main18ClassFromOtherFileC '' false // CHECK-NOMINAL-2-DAG: nominal interface SL '' false // CHECK-NOMINAL-2-DAG: nominal interface s25ExpressibleByFloatLiteralP '' false diff --git a/test/NameBinding/reference-dependencies-members-fine.swift b/test/NameBinding/reference-dependencies-members-fine.swift index c1c9ba58dff74..bbb99fbfb3e98 100644 --- a/test/NameBinding/reference-dependencies-members-fine.swift +++ b/test/NameBinding/reference-dependencies-members-fine.swift @@ -4,9 +4,11 @@ // RUN: %empty-directory(%t) // RUN: cp %s %t/main.swift -// RUN: %target-swift-frontend -enable-fine-grained-dependencies -typecheck -primary-file %t/main.swift %S/Inputs/reference-dependencies-members-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps -// RUN: %target-swift-frontend -enable-fine-grained-dependencies -typecheck -primary-file %t/main.swift %S/Inputs/reference-dependencies-members-helper.swift -emit-reference-dependencies-path - > %t-2.swiftdeps +// Need -fine-grained-dependency-include-intrafile to be invarient wrt type-body-fingerprints enabled/disabled +// RUN: %target-swift-frontend -enable-fine-grained-dependencies -fine-grained-dependency-include-intrafile -typecheck -primary-file %t/main.swift %S/Inputs/reference-dependencies-members-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps + +// RUN: %target-swift-frontend -enable-fine-grained-dependencies -fine-grained-dependency-include-intrafile -typecheck -primary-file %t/main.swift %S/Inputs/reference-dependencies-members-helper.swift -emit-reference-dependencies-path - > %t-2.swiftdeps // RUN: %S/../Inputs/process_fine_grained_swiftdeps.sh <%t.swiftdeps >%t-processed.swiftdeps // RUN: %S/../Inputs/process_fine_grained_swiftdeps.sh <%t-2.swiftdeps >%t-2-processed.swiftdeps @@ -14,7 +16,6 @@ // RUN: %FileCheck -check-prefix=PROVIDES-NOMINAL %s < %t-processed.swiftdeps // RUN: %FileCheck -check-prefix=PROVIDES-NOMINAL-2 %s < %t-processed.swiftdeps -// RUN: %FileCheck -check-prefix=PROVIDES-NOMINAL-NEGATIVE %s < %t-processed.swiftdeps // RUN: %FileCheck -check-prefix=PROVIDES-MEMBER %s < %t-processed.swiftdeps // RUN: %FileCheck -check-prefix=PROVIDES-MEMBER-NEGATIVE %s < %t-processed.swiftdeps // RUN: %FileCheck -check-prefix=DEPENDS-NOMINAL %s < %t-processed.swiftdeps @@ -54,15 +55,13 @@ protocol SomeProto {} // DEPENDS-MEMBER-DAG: member interface 4main10OtherClassC deinit false extension OtherClass : SomeProto {} -// PROVIDES-NOMINAL-NEGATIVE-NOT: nominal implementation 4main11OtherStructV '' true -// PROVIDES-NOMINAL-NEGATIVE-NOT: nominal interface 4main11OtherStructV '' true -// DEPENDS-NOMINAL-DAG: nominal interface 4main11OtherStructV '' false +// PROVIDES-NOMINAL-DAG: nominal implementation 4main11OtherStructV '' true +// PROVIDES-NOMINAL-DAG: nominal interface 4main11OtherStructV '' true extension OtherStruct { // PROVIDES-MEMBER-DAG: potentialMember interface 4main11OtherStructV '' true // PROVIDES-MEMBER-DAG: member interface 4main11OtherStructV foo true // PROVIDES-MEMBER-DAG: member interface 4main11OtherStructV bar true - // PROVIDES-MEMBER-NEGATIVE-NOT: member interface 4main11OtherStructV baz true - // DEPENDS-MEMBER-DAG: member interface 4main11OtherStructV baz false + // PROVIDES-MEMBER-DAG: member interface 4main11OtherStructV baz true // DEPENDS-MEMBER-NEGATIVE-NOT:: potentialMember interface 4main11OtherStructV baz false func foo() {} var bar: () { return () } diff --git a/test/Parse/metatype_object_conversion.swift b/test/Parse/metatype_object_conversion.swift index 96f27402dc86f..2dc87ff1e87bb 100644 --- a/test/Parse/metatype_object_conversion.swift +++ b/test/Parse/metatype_object_conversion.swift @@ -12,15 +12,14 @@ func takesAnyObject(_ x: AnyObject) {} func concreteTypes() { takesAnyObject(C.self) - // TODO: Better error messages - takesAnyObject(S.self) // expected-error{{argument type 'S.Type' does not conform to expected type 'AnyObject'}} - takesAnyObject(ClassConstrainedProto.self) // expected-error{{argument type 'ClassConstrainedProto.Protocol' does not conform to expected type 'AnyObject'}} + takesAnyObject(S.self) // expected-error{{argument type 'S.Type' expected to be an instance of a class or class-constrained type}} + takesAnyObject(ClassConstrainedProto.self) // expected-error{{argument type 'ClassConstrainedProto.Protocol' expected to be an instance of a class or class-constrained type}} } func existentialMetatypes(nonClass: NonClassProto.Type, classConstrained: ClassConstrainedProto.Type, compo: (NonClassProto & ClassConstrainedProto).Type) { - takesAnyObject(nonClass) // expected-error{{argument type 'NonClassProto.Type' does not conform to expected type 'AnyObject'}} + takesAnyObject(nonClass) // expected-error{{argument type 'NonClassProto.Type' expected to be an instance of a class or class-constrained type}} takesAnyObject(classConstrained) takesAnyObject(compo) } diff --git a/test/SILGen/expressions.swift b/test/SILGen/expressions.swift index f642702602900..54654a6ee7b29 100644 --- a/test/SILGen/expressions.swift +++ b/test/SILGen/expressions.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: echo "public var x = Int()" | %target-swift-frontend -module-name FooBar -emit-module -o %t - +// RUN: echo "public var x = Int()" | %target-swift-frontend -parse-as-library -module-name FooBar -emit-module -o %t - // RUN: %target-swift-emit-silgen -parse-stdlib -module-name expressions %s -I%t -disable-access-control | %FileCheck %s import Swift diff --git a/test/SILGen/global_init_attribute.swift b/test/SILGen/global_init_attribute.swift index f47bde0192a73..95167c7127078 100644 --- a/test/SILGen/global_init_attribute.swift +++ b/test/SILGen/global_init_attribute.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-module -o %t %S/Inputs/def_global.swift +// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-as-library -emit-module -o %t %S/Inputs/def_global.swift // RUN: %target-swift-emit-silgen -Xllvm -sil-full-demangle -parse-as-library -I %t %s | %FileCheck %s // // Test that SILGen uses the "global_init" attribute for all global diff --git a/test/SILGen/global_resilience.swift b/test/SILGen/global_resilience.swift index c05720d0713eb..78b425a9ed684 100644 --- a/test/SILGen/global_resilience.swift +++ b/test/SILGen/global_resilience.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_global.swiftmodule -module-name=resilient_global %S/../Inputs/resilient_global.swift +// RUN: %target-swift-frontend -emit-module -parse-as-library -enable-library-evolution -emit-module-path=%t/resilient_global.swiftmodule -module-name=resilient_global %S/../Inputs/resilient_global.swift // RUN: %target-swift-emit-silgen -I %t -enable-library-evolution -parse-as-library %s | %FileCheck %s // RUN: %target-swift-emit-sil -I %t -O -enable-library-evolution -parse-as-library %s | %FileCheck --check-prefix=CHECK-OPT %s diff --git a/test/SILGen/value_ownership_class.swift b/test/SILGen/value_ownership_class.swift new file mode 100644 index 0000000000000..0c8fbe81ea54a --- /dev/null +++ b/test/SILGen/value_ownership_class.swift @@ -0,0 +1,7 @@ +// RUN: %target-swift-emit-silgen %s | %FileCheck %s + +class ConsumingClass { + __consuming func consumingMethod() {} +} + +// CHECK-LABEL: sil hidden [ossa] @$s21value_ownership_class14ConsumingClassC15consumingMethodyyF : $@convention(method) (@owned ConsumingClass) -> () { diff --git a/test/SILGen/without_actually_escaping.swift b/test/SILGen/without_actually_escaping.swift index 2979157df33b5..1d5e1569e627e 100644 --- a/test/SILGen/without_actually_escaping.swift +++ b/test/SILGen/without_actually_escaping.swift @@ -100,3 +100,16 @@ func withoutActuallyEscapingConflict() { modifyAndPerform(&localVar, closure: $0) } } + +// CHECK-LABEL: sil [ossa] @$s25without_actually_escaping0A25ActuallyEscapingCFunction8functionyyyXC_tF +// CHECK: bb0([[ARG:%.*]] : $@convention(c) @noescape () -> ()): +// CHECK: [[E:%.*]] = convert_function [[ARG]] : $@convention(c) @noescape () -> () to [without_actually_escaping] $@convention(c) () -> () +// CHECK: [[F:%.*]] = function_ref @$s25without_actually_escaping0A25ActuallyEscapingCFunction8functionyyyXC_tFyyyXCXEfU_ : $@convention(thin) (@convention(c) () -> ()) -> () +// CHECK: apply [[F]]([[E]]) : $@convention(thin) (@convention(c) () -> ()) -> () +public func withoutActuallyEscapingCFunction(function: (@convention(c) () -> Void)) { + withoutActuallyEscaping(function) { f in + var pointer: UnsafeRawPointer? = nil + pointer = unsafeBitCast(f, to: UnsafeRawPointer.self) + print(pointer) + } +} diff --git a/test/SILOptimizer/diagnose_unreachable.sil b/test/SILOptimizer/diagnose_unreachable.sil index bbf443dc223ec..7045ca9e368ab 100644 --- a/test/SILOptimizer/diagnose_unreachable.sil +++ b/test/SILOptimizer/diagnose_unreachable.sil @@ -782,3 +782,33 @@ bb1(%2 : @owned $Builtin.NativeObject): bb2: unreachable } + +// Test propagation of guaranteed phi arguments. The nested end_borrow +// must be removed, even with the outer borrow is *not* a function +// argument. + +enum EnumWithB { + case A(B) + func testit() -> Int +} + +// CHECK-LABEL: sil hidden [ossa] @testPropagateGuaranteedPhi : $@convention(method) (@guaranteed EnumWithB) -> () { +// CHECK: bb1([[PHI:%.*]] : @guaranteed $B): +// CHECK: br bb2 +// CHECK: bb2: +// CHECK: end_borrow [[PHI]] : $B +// CHECK-NOT: end_borrow +// CHECK-LABEL: } // end sil function 'testPropagateGuaranteedPhi' +sil hidden [ossa] @testPropagateGuaranteedPhi : $@convention(method) (@guaranteed EnumWithB) -> () { +bb0(%0 : @guaranteed $EnumWithB): + switch_enum %0 : $EnumWithB, case #EnumWithB.A!enumelt.1: bb1 + +bb1(%2 : @guaranteed $B): + br bb3(%2 : $B) + +bb3(%4 : @guaranteed $B): + end_borrow %4 : $B + end_borrow %2 : $B + %99 = tuple () + return %99 : $() +} diff --git a/test/SILOptimizer/escape_analysis.sil b/test/SILOptimizer/escape_analysis.sil index eddfac11b7f09..e510fbadcda74 100644 --- a/test/SILOptimizer/escape_analysis.sil +++ b/test/SILOptimizer/escape_analysis.sil @@ -1888,3 +1888,25 @@ bb0(%0 : @guaranteed $@sil_unowned Builtin.NativeObject): %1 = strong_copy_unowned_value %0 : $@sil_unowned Builtin.NativeObject return %1 : $Builtin.NativeObject } + +// Test begin_access. It should look like a derived pointer. +// CHECK-LABEL: CG of testAccessMarkerHelper +sil hidden @testAccessMarkerHelper : $@convention(thin) (@inout SomeData) -> () { +bb0(%0 : $*SomeData): + %1 = tuple () + return %1 : $() +} + +// CHECK-LABEL: CG of testAccessMarker +// CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.1) +// CHECK-NEXT: Con [ref] %0.1 Esc: G, Succ: +// CHECK-LABEL: End +sil hidden @testAccessMarker : $@convention(thin) (@inout SomeData) -> () { +bb0(%0 : $*SomeData): + %1 = begin_access [modify] [static] %0 : $*SomeData + %2 = function_ref @testAccessMarkerHelper : $@convention(thin) (@inout SomeData) -> () + %3 = apply %2(%1) : $@convention(thin) (@inout SomeData) -> () + end_access %1 : $*SomeData + %5 = tuple () + return %5 : $() +} diff --git a/test/Sanitizers/tsan-emptyarraystorage.swift b/test/Sanitizers/tsan-emptyarraystorage.swift index 193a48514bb02..af9deb347e0f8 100644 --- a/test/Sanitizers/tsan-emptyarraystorage.swift +++ b/test/Sanitizers/tsan-emptyarraystorage.swift @@ -6,10 +6,6 @@ // REQUIRES: foundation // UNSUPPORTED: OS=tvos -// FIXME: This should be covered by "tsan_runtime"; older versions of Apple OSs -// don't support TSan. -// UNSUPPORTED: remote_run - import Foundation let sem = DispatchSemaphore(value: 0) diff --git a/test/Sema/circular_decl_checking.swift b/test/Sema/circular_decl_checking.swift index acb78f0520803..3e8d6e2a9a542 100644 --- a/test/Sema/circular_decl_checking.swift +++ b/test/Sema/circular_decl_checking.swift @@ -23,9 +23,10 @@ class HasGenericFunc { } } -class HasProp { +class HasProp { // expected-note {{'HasProp' declared here}} var HasProp: HasProp { - return HasProp() // expected-error {{cannot call value of non-function type 'HasProp'}}{{19-21=}} + return HasProp() // expected-error {{use of 'HasProp' refers to instance method rather than class 'HasProp' in module 'circular_decl_checking'}} + // expected-note@-1 {{use 'circular_decl_checking.' to reference the class in module 'circular_decl_checking'}} {{12-12=circular_decl_checking.}} } var SomethingElse: SomethingElse? { // expected-error {{use of undeclared type 'SomethingElse'}} return nil diff --git a/test/Sema/diag_metatype_cast_to_reference_no_objc.swift b/test/Sema/diag_metatype_cast_to_reference_no_objc.swift index 28566417e0fbf..abca5b92aa279 100644 --- a/test/Sema/diag_metatype_cast_to_reference_no_objc.swift +++ b/test/Sema/diag_metatype_cast_to_reference_no_objc.swift @@ -3,6 +3,6 @@ class C {} func test(c: AnyClass) { - let _: AnyObject = c // expected-error {{value of type 'AnyClass' (aka 'AnyObject.Type') does not conform to specified type 'AnyObject'}} - let _: AnyObject = C.self // expected-error {{value of type 'C.Type' does not conform to specified type 'AnyObject'}} + let _: AnyObject = c // expected-error {{value of type 'AnyClass' (aka 'AnyObject.Type') expected to be instance of class or class-constrained type}} + let _: AnyObject = C.self // expected-error {{value of type 'C.Type' expected to be instance of class or class-constrained type}} } diff --git a/test/Serialization/Recovery/typedefs.swift b/test/Serialization/Recovery/typedefs.swift index a9fab839e045b..60d0eda010d56 100644 --- a/test/Serialization/Recovery/typedefs.swift +++ b/test/Serialization/Recovery/typedefs.swift @@ -1,4 +1,7 @@ // RUN: %empty-directory(%t) + +// Cannot use -parse-as-library here because that would compile also the +// #if VERIFY path, which contains top-level code. // RUN: %target-swift-frontend -emit-sil -o - -emit-module-path %t/Lib.swiftmodule -module-name Lib -I %S/Inputs/custom-modules -disable-objc-attr-requires-foundation-module -enable-objc-interop %s | %FileCheck -check-prefix CHECK-VTABLE %s // RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules | %FileCheck %s @@ -23,9 +26,9 @@ import Lib // CHECK-SIL-LABEL: sil hidden [ossa] @$s8typedefs11testSymbolsyyF func testSymbols() { // Check that the symbols are not using 'Bool'. - // CHECK-SIL: function_ref @$s3Lib1xs5Int32Vvau + // CHECK-SIL: global_addr @$s3Lib9usesAssocs5Int32VSgvp _ = Lib.x - // CHECK-SIL: function_ref @$s3Lib9usesAssocs5Int32VSgvau + // CHECK-SIL: global_addr @$s3Lib1xs5Int32Vvp _ = Lib.usesAssoc } // CHECK-SIL: end sil function '$s8typedefs11testSymbolsyyF' diff --git a/test/Serialization/multi-file-nested-type-extension.swift b/test/Serialization/multi-file-nested-type-extension.swift index fd2d139a25009..181fc38b72c52 100644 --- a/test/Serialization/multi-file-nested-type-extension.swift +++ b/test/Serialization/multi-file-nested-type-extension.swift @@ -10,7 +10,7 @@ // REQUIRES: asserts // CHECK: Statistics -// CHECK: 1 Serialization - # of nested types resolved without full lookup +// CHECK: 2 Serialization - # of nested types resolved without full lookup // Note the Optional here and below; this was once necessary to produce a crash. // Without it, the type of the parameter is initialized "early" enough to not @@ -21,3 +21,9 @@ extension Outer { public func useTypes(_: Outer.Callback?) {} } + +extension OuterClass.Inner { + public static var instance: OuterClass.Inner { + return OuterClass.Inner() + } +} diff --git a/test/decl/nested/protocol.swift b/test/decl/nested/protocol.swift index ea5c973467b10..6d25970753ba7 100644 --- a/test/decl/nested/protocol.swift +++ b/test/decl/nested/protocol.swift @@ -19,7 +19,7 @@ class OuterGenericClass { } } -protocol OuterProtocol { // expected-note{{'OuterProtocol' declared here}} +protocol OuterProtocol { associatedtype Hen protocol InnerProtocol { // expected-error{{protocol 'InnerProtocol' cannot be nested inside another declaration}} associatedtype Rooster @@ -32,7 +32,7 @@ struct ConformsToOuterProtocol : OuterProtocol { typealias Hen = Int func f() { let _ = InnerProtocol.self } - // expected-error@-1 {{use of unresolved identifier 'InnerProtocol'}} + // expected-error@-1 {{protocol 'InnerProtocol' can only be used as a generic constraint because it has Self or associated type requirements}} } protocol Racoon { diff --git a/test/decl/protocol/protocols.swift b/test/decl/protocol/protocols.swift index f0b6bf4977bc6..2ed52c88bd3b7 100644 --- a/test/decl/protocol/protocols.swift +++ b/test/decl/protocol/protocols.swift @@ -101,9 +101,10 @@ struct DoesNotConform : Up { // Circular protocols -protocol CircleMiddle : CircleStart { func circle_middle() } // expected-error 3 {{protocol 'CircleMiddle' refines itself}} -protocol CircleStart : CircleEnd { func circle_start() } -// expected-note@-1 3 {{protocol 'CircleStart' declared here}} +protocol CircleMiddle : CircleStart { func circle_middle() } // expected-error 2 {{protocol 'CircleMiddle' refines itself}} +// expected-note@-1 {{protocol 'CircleMiddle' declared here}} +protocol CircleStart : CircleEnd { func circle_start() } // expected-error {{protocol 'CircleStart' refines itself}} +// expected-note@-1 2 {{protocol 'CircleStart' declared here}} protocol CircleEnd : CircleMiddle { func circle_end()} // expected-note 3 {{protocol 'CircleEnd' declared here}} protocol CircleEntry : CircleTrivial { } diff --git a/test/type/self.swift b/test/type/self.swift index bc2fa859cb96b..10e27b93a4e6e 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -270,3 +270,20 @@ class Foo { Self.value * 2 }() } + +// https://bugs.swift.org/browse/SR-11681 - duplicate diagnostics +struct Box { + let boxed: T +} + +class Boxer { + lazy var s = Box(boxed: self as! Self) + // expected-error@-1 {{stored property cannot have covariant 'Self' type}} + // expected-error@-2 {{mutable property cannot have covariant 'Self' type}} + + var t = Box(boxed: Self()) + // expected-error@-1 {{stored property cannot have covariant 'Self' type}} + // expected-error@-2 {{covariant 'Self' type cannot be referenced from a stored property initializer}} + + required init() {} +} diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index 1ebbcfeb25441..1e2b1fd10a211 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -539,11 +539,6 @@ bool SwiftASTManager::initCompilerInvocation( // We don't care about LLVMArgs FrontendOpts.LLVMArgs.clear(); - // This validation may call stat(2) many times. Disable it to prevent - // performance issues. - Invocation.getSearchPathOptions().DisableModulesValidateSystemDependencies = - true; - // SwiftSourceInfo files provide source location information for decls coming // from loaded modules. For most IDE use cases it either has an undesirable // impact on performance with no benefit (code completion), results in stale diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index fb2b67b7225fb..995eaaaab5eef 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -3436,8 +3436,6 @@ int main(int argc, char *argv[]) { options::DebugForbidTypecheckPrefix; InitInvok.getTypeCheckerOptions().DebugConstraintSolver = options::DebugConstraintSolver; - InitInvok.getSearchPathOptions().DisableModulesValidateSystemDependencies = - true; for (auto ConfigName : options::BuildConfigs) InitInvok.getLangOptions().addCustomConditionalCompilationFlag(ConfigName); diff --git a/unittests/Driver/FineGrainedDependencyGraphTests.cpp b/unittests/Driver/FineGrainedDependencyGraphTests.cpp index b8af2dddc03a7..28e8286866d9e 100644 --- a/unittests/Driver/FineGrainedDependencyGraphTests.cpp +++ b/unittests/Driver/FineGrainedDependencyGraphTests.cpp @@ -808,3 +808,19 @@ TEST(ModuleDepGraph, MutualInterfaceHash) { const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); EXPECT_TRUE(contains(jobs, &job1)); } + +TEST(ModuleDepGraph, DisabledTypeBodyFingerprints) { + ModuleDepGraph graph(/*EnableTypeFingerprints=*/ false); + + graph.simulateLoad(&job0, {{dependsNominal, {"B2"}}}); + graph.simulateLoad(&job1, {{providesNominal, {"B1", "B2"}}}); + graph.simulateLoad(&job2, {{dependsNominal, {"B1"}}}); + + { + const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job1); + EXPECT_EQ(3u, jobs.size()); + EXPECT_TRUE(contains(jobs, &job0)); + EXPECT_TRUE(contains(jobs, &job1)); + EXPECT_TRUE(contains(jobs, &job2)); + } +} diff --git a/unittests/Driver/TypeBodyFingerprintsDependencyGraphTests.cpp b/unittests/Driver/TypeBodyFingerprintsDependencyGraphTests.cpp index ff06b0344c252..041cc9c2ee416 100644 --- a/unittests/Driver/TypeBodyFingerprintsDependencyGraphTests.cpp +++ b/unittests/Driver/TypeBodyFingerprintsDependencyGraphTests.cpp @@ -808,3 +808,24 @@ TEST(ModuleDepGraphWithTypeBodyFingerprints, MutualInterfaceHash) { const auto jobs = graph.findJobsToRecompileWhenWholeJobChanges(&job0); EXPECT_TRUE(contains(jobs, &job1)); } + +TEST(ModuleDepGraph, EnabledTypeBodyFingerprints) { + ModuleDepGraph graph(/*EnableTypeFingerprints=*/ true); + + graph.simulateLoad(&job0, {{dependsNominal, {"B2"}}}); + graph.simulateLoad(&job1, {{providesNominal, {"B1", "B2"}}}); + graph.simulateLoad(&job2, {{dependsNominal, {"B1"}}}); + + + const DependencyKey k = DependencyKey(NodeKind::nominal, + DeclAspect::interface, "B1", ""); + std::vector changedNodes; + graph.forEachMatchingNode( + k, + [&](ModuleDepGraphNode* n) {changedNodes.push_back(n);}); + { + const auto jobs = graph.findJobsToRecompileWhenNodesChange(changedNodes); + EXPECT_TRUE(contains(jobs, &job2)); + EXPECT_FALSE(contains(jobs, &job0)); + } +} diff --git a/utils/build-script-impl b/utils/build-script-impl index b5b3264410f36..255ac4beb3844 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1416,7 +1416,7 @@ for host in "${ALL_HOSTS[@]}"; do module_cache="${build_dir}/module-cache" # Add any specific cmake options specified by build-script - product_cmake_options_name=$(to_varname "${product}")_CMAKE_OPTIONS + product_cmake_options_name=$(to_varname "${product/_static}")_CMAKE_OPTIONS product_cmake_options=(${!product_cmake_options_name}) # convert to array cmake_options+=("${product_cmake_options[@]}") diff --git a/utils/build_swift/build_swift/cache_utils.py b/utils/build_swift/build_swift/cache_utils.py new file mode 100644 index 0000000000000..ede762d7d2c78 --- /dev/null +++ b/utils/build_swift/build_swift/cache_utils.py @@ -0,0 +1,69 @@ +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See https://swift.org/LICENSE.txt for license information +# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + + +""" +Cache related utitlity functions and decorators. +""" + + +from __future__ import absolute_import, unicode_literals + +import functools + + +__all__ = [ + 'cache', + 'reify', +] + + +def cache(func): + """Decorator that caches result of a function call. + + NOTE: This decorator does not play nice with methods as the created cache + is not instance-local, rather it lives in the decorator. + NOTE: When running in Python 3.2 or newer this decorator is replaced with + the standard `functools.lru_cache` using a maxsize of None. + """ + + # Use the standard functools.lru_cache decorator for Python 3.2 and newer. + if hasattr(functools, 'lru_cache'): + return functools.lru_cache(maxsize=None)(func) + + # Otherwise use a naive caching strategy. + _cache = {} + + @functools.wraps(func) + def wrapper(*args, **kwargs): + key = tuple(args) + tuple(kwargs.items()) + + if key not in _cache: + result = func(*args, **kwargs) + _cache[key] = result + return result + + return _cache[key] + return wrapper + + +def reify(func): + """Decorator that replaces the wrapped method with the result after the + first call. Used to wrap property-like methods with no arguments. + """ + + class wrapper(object): + def __get__(self, obj, type=None): + if obj is None: + return self + + result = func(obj) + setattr(obj, func.__name__, result) + return result + + return functools.update_wrapper(wrapper(), func) diff --git a/utils/build_swift/tests/build_swift/test_cache_utils.py b/utils/build_swift/tests/build_swift/test_cache_utils.py new file mode 100644 index 0000000000000..8dba0d434c49c --- /dev/null +++ b/utils/build_swift/tests/build_swift/test_cache_utils.py @@ -0,0 +1,121 @@ +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See https://swift.org/LICENSE.txt for license information +# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + + +from __future__ import absolute_import, unicode_literals + +import unittest + +from build_swift import cache_utils + +from .. import utils + + +try: + # Python 3.3 + from unittest import mock +except ImportError: + mock = None + + +class _CallCounter(object): + """Callable helper class used to count and return the number of times an + instance has been called. + """ + + def __init__(self): + self._counter = 0 + + def __call__(self, *args, **kwargs): + count = self._counter + self._counter += 1 + return count + + +class TestCache(unittest.TestCase): + """Unit tests for the cache decorator in the cache_utils module. + """ + + @utils.requires_module('unittest.mock') + @utils.requires_python('3.2') # functools.lru_cache + def test_replaced_with_functools_lru_cache_python_3_2(self): + with mock.patch('functools.lru_cache') as mock_lru_cache: + @cache_utils.cache + def func(): + return None + + mock_lru_cache.assert_called() + + def test_call_with_no_args(self): + # Increments the counter once per unique call. + counter = _CallCounter() + + @cache_utils.cache + def func(*args, **kwargs): + return counter(*args, **kwargs) + + self.assertEqual(func(), 0) + self.assertEqual(func(), 0) + + def test_call_with_args(self): + # Increments the counter once per unique call. + counter = _CallCounter() + + @cache_utils.cache + def func(*args, **kwargs): + return counter(*args, **kwargs) + + self.assertEqual(func(0), 0) + self.assertEqual(func(0), 0) + + self.assertEqual(func(1), 1) + self.assertEqual(func(1), 1) + + self.assertEqual(func(2), 2) + self.assertEqual(func(2), 2) + + def test_call_with_args_and_kwargs(self): + # Increments the counter once per unique call. + counter = _CallCounter() + + @cache_utils.cache + def func(*args, **kwargs): + return counter(*args, **kwargs) + + self.assertEqual(func(n=0), 0) + self.assertEqual(func(n=0), 0) + + self.assertEqual(func(a=1, b='b'), 1) + self.assertEqual(func(a=1, b='b'), 1) + + self.assertEqual(func(0, x=1, y=2.0), 2) + self.assertEqual(func(0, x=1, y=2.0), 2) + + +class TestReify(unittest.TestCase): + """Unit tests for the reify decorator in the cache_utils module. + """ + + def test_replaces_attr_after_first_call(self): + class Counter(object): + def __init__(self): + self._counter = 0 + + @cache_utils.reify + def count(self): + count = self._counter + self._counter += 1 + return count + + counter = Counter() + + self.assertEqual(counter.count, 0) + self.assertEqual(counter.count, 0) + + # Assert that the count property has been replaced with the constant. + self.assertEqual(getattr(counter, 'count'), 0) diff --git a/utils/build_swift/tests/utils.py b/utils/build_swift/tests/utils.py index c21d8361bb8fd..85fc24350e9ff 100644 --- a/utils/build_swift/tests/utils.py +++ b/utils/build_swift/tests/utils.py @@ -15,9 +15,11 @@ import sys import unittest -from six import StringIO +from build_swift import cache_utils +from build_swift.versions import Version -from swift_build_support.swift_build_support import cache_util +import six +from six import StringIO __all__ = [ @@ -27,6 +29,7 @@ 'requires_attr', 'requires_module', 'requires_platform', + 'requires_python', 'BUILD_SCRIPT_IMPL_PATH', 'BUILD_SWIFT_PATH', @@ -38,6 +41,8 @@ # ----------------------------------------------------------------------------- # Constants +_PYTHON_VERSION = Version(platform.python_version()) + TESTS_PATH = os.path.abspath(os.path.dirname(__file__)) BUILD_SWIFT_PATH = os.path.abspath(os.path.join(TESTS_PATH, os.pardir)) UTILS_PATH = os.path.abspath(os.path.join(BUILD_SWIFT_PATH, os.pardir)) @@ -124,9 +129,10 @@ def __exit__(self, exc_type, exc_value, traceback): sys.stderr = self._old_stdout -@cache_util.cached +@cache_utils.cache def requires_attr(obj, attr): - """ + """Decorator used to skip tests if an object does not have the required + attribute. """ try: @@ -137,7 +143,7 @@ def requires_attr(obj, attr): attr, obj)) -@cache_util.cached +@cache_utils.cache def requires_module(fullname): """Decorator used to skip tests if a module is not imported. """ @@ -148,7 +154,7 @@ def requires_module(fullname): return unittest.skip('Unable to import "{}"'.format(fullname)) -@cache_util.cached +@cache_utils.cache def requires_platform(name): """Decorator used to skip tests if not running on the given platform. """ @@ -157,4 +163,20 @@ def requires_platform(name): return lambda func: func return unittest.skip( - 'Required platform "{}"" does not match system'.format(name)) + 'Required platform "{}" does not match system'.format(name)) + + +@cache_utils.cache +def requires_python(version): + """Decorator used to skip tests if the running Python version is not + greater or equal to the required version. + """ + + if isinstance(version, six.string_types): + version = Version(version) + + if _PYTHON_VERSION >= version: + return lambda func: func + + return unittest.skip( + 'Requires Python version {} or greater'.format(version)) diff --git a/utils/swift_build_support/swift_build_support/cache_util.py b/utils/swift_build_support/swift_build_support/cache_util.py deleted file mode 100644 index 493b558ea9084..0000000000000 --- a/utils/swift_build_support/swift_build_support/cache_util.py +++ /dev/null @@ -1,58 +0,0 @@ -# swift_build_support/cache_util.py -----------------------------*- python -*- -# -# This source file is part of the Swift.org open source project -# -# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -# Licensed under Apache License v2.0 with Runtime Library Exception -# -# See https://swift.org/LICENSE.txt for license information -# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -# -# ---------------------------------------------------------------------------- -""" -Cache related utilities -""" -# ---------------------------------------------------------------------------- - -from functools import update_wrapper - -__all__ = [ - 'cached', - 'reify' -] - - -def cached(func): - """Decorator that caches result of method or function. - - Note: Support method or function. - """ - cache = {} - - def wrapper(*args, **kwargs): - key = tuple(args) + tuple(kwargs.items()) - if key not in cache: - result = func(*args, **kwargs) - cache[key] = result - return result - else: - return cache[key] - - return update_wrapper(wrapper, func) - - -def reify(func): - """Decorator that replaces the wrapped method with the result after the - first call. - - Note: Support method that takes no arguments. - """ - class Wrapper(object): - def __get__(self, obj, objtype=None): - if obj is None: - return self - result = func(obj) - setattr(obj, func.__name__, result) - return result - - return update_wrapper(Wrapper(), func) diff --git a/utils/swift_build_support/swift_build_support/products/ninja.py b/utils/swift_build_support/swift_build_support/products/ninja.py index 0ffd054ccafc4..53ebb15c6e32e 100644 --- a/utils/swift_build_support/swift_build_support/products/ninja.py +++ b/utils/swift_build_support/swift_build_support/products/ninja.py @@ -18,10 +18,10 @@ import platform import sys +from build_swift.build_swift import cache_utils from build_swift.build_swift.wrappers import xcrun from . import product -from .. import cache_util from .. import shell @@ -44,7 +44,7 @@ def __init__(self, product_class, args, toolchain, workspace): self.args = args self.toolchain = toolchain - @cache_util.reify + @cache_utils.reify def ninja_bin_path(self): return os.path.join(self.build_dir, 'ninja') diff --git a/utils/swift_build_support/swift_build_support/toolchain.py b/utils/swift_build_support/swift_build_support/toolchain.py index 1395397a80332..b7c8247374e2a 100644 --- a/utils/swift_build_support/swift_build_support/toolchain.py +++ b/utils/swift_build_support/swift_build_support/toolchain.py @@ -18,10 +18,10 @@ import platform +from build_swift.build_swift import cache_utils from build_swift.build_swift.shell import which from build_swift.build_swift.wrappers import xcrun -from . import cache_util from . import shell @@ -44,7 +44,7 @@ def _register(name, *tool): def _getter(self): return self.find_tool(*tool) _getter.__name__ = name - setattr(Toolchain, name, cache_util.reify(_getter)) + setattr(Toolchain, name, cache_utils.reify(_getter)) if platform.system() == 'Windows': @@ -162,7 +162,7 @@ def __init__(self): suffixes = ['38', '37', '36', '35'] super(FreeBSD, self).__init__(suffixes) - @cache_util.reify + @cache_utils.reify def _release_date(self): """Return the release date for FreeBSD operating system on this host. If the release date cannot be ascertained, return None. diff --git a/utils/swift_build_support/tests/test_cache_util.py b/utils/swift_build_support/tests/test_cache_util.py deleted file mode 100644 index c65f308b48295..0000000000000 --- a/utils/swift_build_support/tests/test_cache_util.py +++ /dev/null @@ -1,99 +0,0 @@ -# tests/test_cache_util.py --------------------------------------*- python -*- -# -# This source file is part of the Swift.org open source project -# -# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -# Licensed under Apache License v2.0 with Runtime Library Exception -# -# See https://swift.org/LICENSE.txt for license information -# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -# -# ---------------------------------------------------------------------------- - -import unittest - -from swift_build_support import cache_util - - -my_func_called = 0 -my_kfunc_called = 0 - - -@cache_util.cached -def my_func(arg1, arg2): - global my_func_called - my_func_called += 1 - return "my_func_result(%s, %s)" % (arg1, arg2) - - -@cache_util.cached -def my_kfunc(arg1, arg2): - global my_kfunc_called - my_kfunc_called += 1 - return "my_kfunc_result(%s, %s)" % (arg1, arg2) - - -class MyClass(object): - def __init__(self, prop=None): - self.my_method_called = 0 - self.my_prop_called = 0 - self.prop_value = prop - - @cache_util.cached - def my_method(self, arg1, arg2): - self.my_method_called += 1 - return "my_meth_result(%s, %s)" % (arg1, arg2) - - @cache_util.reify - def my_prop(self): - self.my_prop_called += 1 - return "==%s==" % (self.prop_value) - - -class CacheUtilTestCase(unittest.TestCase): - def test_cached_func(self): - self.assertEqual(my_func("foo", 42), "my_func_result(foo, 42)") - self.assertEqual(my_func_called, 1) - self.assertEqual(my_func("foo", 42), "my_func_result(foo, 42)") - self.assertEqual(my_func_called, 1) - self.assertEqual(my_func("bar", 42), "my_func_result(bar, 42)") - self.assertEqual(my_func_called, 2) - self.assertEqual(my_func("foo", 42), "my_func_result(foo, 42)") - self.assertEqual(my_func_called, 2) - - def test_cached_kwfunc(self): - self.assertEqual(my_kfunc("foo", arg2=42), "my_kfunc_result(foo, 42)") - self.assertEqual(my_kfunc_called, 1) - self.assertEqual(my_kfunc("foo", arg2=42), "my_kfunc_result(foo, 42)") - self.assertEqual(my_kfunc_called, 1) - self.assertEqual(my_kfunc("bar", arg2=42), "my_kfunc_result(bar, 42)") - self.assertEqual(my_kfunc_called, 2) - self.assertEqual(my_kfunc("foo", arg2=42), "my_kfunc_result(foo, 42)") - self.assertEqual(my_kfunc_called, 2) - - def test_cached_method(self): - obj1 = MyClass() - self.assertEqual(obj1.my_method("foo", 42), "my_meth_result(foo, 42)") - self.assertEqual(obj1.my_method_called, 1) - self.assertEqual(obj1.my_method("foo", 42), "my_meth_result(foo, 42)") - self.assertEqual(obj1.my_method_called, 1) - self.assertEqual(obj1.my_method("bar", 12), "my_meth_result(bar, 12)") - self.assertEqual(obj1.my_method_called, 2) - - # Test for instance independency. - obj2 = MyClass() - self.assertEqual(obj2.my_method("foo", 42), "my_meth_result(foo, 42)") - self.assertEqual(obj2.my_method_called, 1) - self.assertEqual(obj1.my_method_called, 2) - - def test_reify(self): - obj1 = MyClass(prop='foo') - self.assertEqual(obj1.my_prop, '==foo==') - self.assertEqual(obj1.my_prop_called, 1) - self.assertEqual(obj1.my_prop, '==foo==') - self.assertEqual(obj1.my_prop_called, 1) - - # Test for instance independency. - obj2 = MyClass(prop='bar') - self.assertEqual(obj2.my_prop, '==bar==') - self.assertEqual(obj1.my_prop, '==foo==') diff --git a/validation-test/Driver/Dependencies/rdar23148987-type-fingerprints.swift b/validation-test/Driver/Dependencies/rdar23148987-type-fingerprints.swift new file mode 100644 index 0000000000000..3eefcdd073ba8 --- /dev/null +++ b/validation-test/Driver/Dependencies/rdar23148987-type-fingerprints.swift @@ -0,0 +1,61 @@ +// RUN: %empty-directory(%t) + +// RUN: cp %s %t/main.swift +// RUN: cp %S/Inputs/rdar23148987/helper-1.swift %t/helper.swift +// RUN: touch -t 201401240005 %t/*.swift + +// RUN: cd %t && %target-build-swift -enable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1 %s + +// CHECK-1-NOT: warning +// CHECK-1: {{^{$}} +// CHECK-1: "kind": "began" +// CHECK-1: "name": "compile" +// CHECK-1: ".\/main.swift" +// CHECK-1: {{^}$}} + +// CHECK-1: {{^{$}} +// CHECK-1: "kind": "began" +// CHECK-1: "name": "compile" +// CHECK-1: ".\/helper.swift" +// CHECK-1: {{^}$}} + +// RUN: ls %t/ | %FileCheck -check-prefix=CHECK-LS %s + +// CHECK-LS-DAG: main.o +// CHECK-LS-DAG: helper.o + +// RUN: cd %t && %target-build-swift -enable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1-SKIPPED %s + +// CHECK-1-SKIPPED-NOT: warning +// CHECK-1-SKIPPED: {{^{$}} +// CHECK-1-SKIPPED: "kind": "skipped" +// CHECK-1-SKIPPED: "name": "compile" +// CHECK-1-SKIPPED: ".\/main.swift" +// CHECK-1-SKIPPED: {{^}$}} + +// CHECK-1-SKIPPED: {{^{$}} +// CHECK-1-SKIPPED: "kind": "skipped" +// CHECK-1-SKIPPED: "name": "compile" +// CHECK-1-SKIPPED: ".\/helper.swift" +// CHECK-1-SKIPPED: {{^}$}} + +// RUN: cp %S/Inputs/rdar23148987/helper-2.swift %t/helper.swift +// RUN: touch -t 201401240006 %t/helper.swift +// RUN: cd %t && %target-build-swift -enable-type-fingerprints -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 -driver-show-incremental -driver-show-job-lifecycle | %FileCheck -check-prefix=CHECK-2 %s + +// CHECK-2-NOT: warning +// CHECK-2: {{^{$}} +// CHECK-2: "kind": "began" +// CHECK-2: "name": "compile" +// CHECK-2: ".\/helper.swift" +// CHECK-2: {{^}$}} + +// CHECK-2: {{^{$}} +// CHECK-2: "kind": "began" +// CHECK-2: "name": "compile" +// CHECK-2: ".\/main.swift" +// CHECK-2: {{^}$}} + +func test(obj: Test) { + obj.foo() +} diff --git a/validation-test/Serialization/rdar40839486.swift b/validation-test/Serialization/rdar40839486.swift index 3704eec44bf09..8c4e1531b0db1 100644 --- a/validation-test/Serialization/rdar40839486.swift +++ b/validation-test/Serialization/rdar40839486.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-build-swift -disable-type-fingerprints -emit-module-path %t/main4.swiftmodule -swift-version 4 -Fsystem %sdk/System/Library/PrivateFrameworks/ %s -// RUN: %target-build-swift -disable-type-fingerprints -emit-module-path %t/main4_2.swiftmodule -swift-version 4.2 -Fsystem %sdk/System/Library/PrivateFrameworks/ %s +// RUN: %target-build-swift -emit-module-path %t/main4.swiftmodule -swift-version 4 -Fsystem %sdk/System/Library/PrivateFrameworks/ %s +// RUN: %target-build-swift -emit-module-path %t/main4_2.swiftmodule -swift-version 4.2 -Fsystem %sdk/System/Library/PrivateFrameworks/ %s // REQUIRES: OS=macosx || OS=ios diff --git a/validation-test/stdlib/StringSlicesConcurrentAppend.swift b/validation-test/stdlib/StringSlicesConcurrentAppend.swift index 64441e7a184ea..942449e9dfdc8 100644 --- a/validation-test/stdlib/StringSlicesConcurrentAppend.swift +++ b/validation-test/stdlib/StringSlicesConcurrentAppend.swift @@ -111,8 +111,7 @@ StringTestSuite.test("SliceConcurrentAppend") { expectEqual(0, joinRet1) expectEqual(0, joinRet2) - ret = _stdlib_thread_barrier_destroy(barrierVar!) - expectEqual(0, ret) + _stdlib_thread_barrier_destroy(barrierVar!) barrierVar!.deinitialize(count: 1) barrierVar!.deallocate()