diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 97b87a981cb53..73850a3ccf4c0 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -230,10 +230,6 @@ class ASTContext { /// Cache of remapped types (useful for diagnostics). llvm::StringMap RemappedTypes; - - /// Cache for generic mangling signatures. - llvm::DenseMap, - CanGenericSignature> ManglingSignatures; private: /// \brief The current generation number, which reflects the number of @@ -838,12 +834,6 @@ class ASTContext { ArchetypeBuilder *getOrCreateArchetypeBuilder(CanGenericSignature sig, ModuleDecl *mod); - /// Set the stored archetype builder for the given canonical generic - /// signature and module. - void setArchetypeBuilder(CanGenericSignature sig, - ModuleDecl *mod, - std::unique_ptr builder); - /// Retrieve the inherited name set for the given class. const InheritedNameSet *getAllPropertyNames(ClassDecl *classDecl, bool forInstance); diff --git a/include/swift/AST/ArchetypeBuilder.h b/include/swift/AST/ArchetypeBuilder.h index 9c7a5b058bfb2..00ca1bedac2f6 100644 --- a/include/swift/AST/ArchetypeBuilder.h +++ b/include/swift/AST/ArchetypeBuilder.h @@ -63,15 +63,21 @@ class RequirementSource { /// The requirement was explicitly stated in the generic parameter /// clause. Explicit, - /// The requirement was explicitly stated in the generic parameter clause - /// but is redundant with some other requirement. - Redundant, - /// The requirement was part of a protocol requirement, e.g., an - /// inherited protocol or a requirement on an associated type. - Protocol, - /// - /// The requirement was inferred from part of the signature. + /// The requirement was inferred from the function's parameter or + /// result types. Inferred, + + /// The requirement was part of a protocol requirement on an + /// associated type. + /// + /// These are dropped when building the GenericSignature. + Protocol, + + /// The requirement is redundant with some other requirement. + /// + /// These are dropped when building the GenericSignature. + Redundant, + /// The requirement came from an outer scope. /// FIXME: eliminate this in favor of keeping requirement sources in /// GenericSignatures, at least non-canonical ones? @@ -242,9 +248,10 @@ class ArchetypeBuilder { /// \brief Add all of a generic signature's parameters and requirements. /// /// FIXME: Requirements from the generic signature are treated as coming from - /// an outer scope in order to avoid disturbing the AllDependentTypes. - /// Setting \c treatRequirementsAsExplicit to true disables this behavior. - void addGenericSignature(GenericSignature *sig, bool adoptArchetypes, + /// an outer scope. Setting \c treatRequirementsAsExplicit to true disables + /// this behavior. + void addGenericSignature(GenericSignature *sig, + GenericEnvironment *genericEnv, bool treatRequirementsAsExplicit = false); /// \brief Get a generic signature based on the provided complete list @@ -342,13 +349,6 @@ class ArchetypeBuilder { using SameTypeRequirement = std::pair>; - - /// Retrieve the set of same-type requirements that apply to the potential - /// archetypes known to this builder. - ArrayRef getSameTypeRequirements() const; - - // FIXME: Compute the set of 'extra' witness tables needed to express this - // requirement set. /// \brief Dump all of the requirements, both specified and inferred. LLVM_ATTRIBUTE_DEPRECATED( @@ -617,15 +617,15 @@ class ArchetypeBuilder::PotentialArchetype { } void setIsRecursive() { IsRecursive = true; } - bool isRecursive() { return IsRecursive; } + bool isRecursive() const { return IsRecursive; } - bool isInvalid() { return Invalid; } + bool isInvalid() const { return Invalid; } void setInvalid() { Invalid = true; } /// Determine whether this archetype was renamed due to typo /// correction. If so, \c getName() retrieves the new name. - bool wasRenamed() { return Renamed; } + bool wasRenamed() const { return Renamed; } /// Note that this potential archetype was renamed (due to typo /// correction), providing the new name. @@ -636,7 +636,7 @@ class ArchetypeBuilder::PotentialArchetype { /// Whether this potential archetype makes a better archetype anchor than /// the given archetype anchor. - bool isBetterArchetypeAnchor(PotentialArchetype *other); + bool isBetterArchetypeAnchor(PotentialArchetype *other) const; void dump(llvm::raw_ostream &Out, SourceManager *SrcMgr, unsigned Indent); diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 817f59634f183..892bcfd112bc8 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1332,8 +1332,8 @@ NOTE(no_witnesses_type,none, "protocol requires nested type %0; do you want to add it?", (Identifier)) NOTE(default_associated_type_req_fail,none, "default type %0 for associated type %1 (from protocol %2) " - "does not conform to %3", - (Type, DeclName, Type, Type)) + "does not %select{inherit from|conform to}4 %3", + (Type, DeclName, Type, Type, bool)) ERROR(associated_type_access,none, "associated type in " "%select{PRIVATE|a fileprivate|an internal|a public}0 protocol uses " @@ -1346,8 +1346,8 @@ NOTE(bad_associated_type_deduction,none, (DeclName, DeclName)) NOTE(associated_type_deduction_witness_failed,none, "inferred type %1 (by matching requirement %0) is invalid: " - "does not conform to %2", - (DeclName, Type, DeclName)) + "does not %select{inherit from|conform to}3 %2", + (DeclName, Type, DeclName, bool)) NOTE(ambiguous_associated_type_deduction,none, "ambiguous inference of associated type %0: %1 vs. %2", (DeclName, Type, Type)) @@ -1405,7 +1405,8 @@ NOTE(protocol_witness_not_objc,none, NOTE(protocol_witness_type,none, "possibly intended match", ()) NOTE(protocol_witness_nonconform_type,none, - "possibly intended match %0 does not conform to %1", (Type, Type)) + "possibly intended match %0 does not " + "%select{inherit from|conform to}2 %1", (Type, Type, bool)) NOTE(protocol_requirement_here,none, "requirement %0 declared here", (DeclName)) diff --git a/include/swift/AST/GenericEnvironment.h b/include/swift/AST/GenericEnvironment.h index 14592b4a4b6b1..0f93c998f40d9 100644 --- a/include/swift/AST/GenericEnvironment.h +++ b/include/swift/AST/GenericEnvironment.h @@ -69,6 +69,8 @@ class GenericEnvironment final { ArrayRef getForwardingSubstitutions(ModuleDecl *M, GenericSignature *sig) const; + + void dump() const; }; } // end namespace swift diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index 9768dbd9ad7a7..a69184bf6493c 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -28,6 +28,9 @@ namespace swift { class ArchetypeBuilder; class ProtocolType; +using TypeConformanceMap + = llvm::DenseMap>; + /// Iterator that walks the generic parameter types declared in a generic /// signature and their dependent members. class GenericSignatureWitnessIterator { @@ -171,15 +174,27 @@ class GenericSignature final : public llvm::FoldingSetNode, /// the order of generic parameters in getGenericParams(). TypeSubstitutionMap getSubstitutionMap(ArrayRef args) const; + /// Variant of the above that also returns conformances. + void getSubstitutionMap(ArrayRef subs, + TypeSubstitutionMap &subMap, + TypeConformanceMap &conformanceMap) const; + using LookupConformanceFn = - llvm::function_ref; + llvm::function_ref; /// Build an array of substitutions from an interface type substitution map, /// using the given function to look up conformances. void getSubstitutions(ModuleDecl &mod, - const TypeSubstitutionMap &subs, + const TypeSubstitutionMap &subMap, LookupConformanceFn lookupConformance, - SmallVectorImpl &result); + SmallVectorImpl &result) const; + + /// Build an array of substitutions from an interface type substitution map, + /// using the given function to look up conformances. + void getSubstitutions(ModuleDecl &mod, + const TypeSubstitutionMap &subMap, + const TypeConformanceMap &conformanceMap, + SmallVectorImpl &result) const; /// Return a range that iterates through first all of the generic parameters /// of the signature, followed by all of their recursive member types exposed @@ -195,16 +210,6 @@ class GenericSignature final : public llvm::FoldingSetNode, /// Canonicalize the components of a generic signature. CanGenericSignature getCanonicalSignature() const; - - /// Canonicalize a generic signature down to its essential requirements, - /// for mangling purposes. - /// - /// TODO: This is what getCanonicalSignature() ought to do, but currently - /// does not due to former implementation dependencies on - /// 'getAllDependentTypes' order matching 'getAllArchetypes' order of a - /// generic param list. Now that 'getAllArchetypes' is gone, we might - /// be able to move forward here. - CanGenericSignature getCanonicalManglingSignature(ModuleDecl &M) const; /// Uniquing for the ASTContext. void Profile(llvm::FoldingSetNodeID &ID) { diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 25a7393aaccdf..87f113bf1a54e 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -952,7 +952,7 @@ class SourceFile final : public FileUnit { SourceLoc diagLoc = {}); /// @} - ReferencedNameTracker *getReferencedNameTracker() { + ReferencedNameTracker *getReferencedNameTracker() const { return ReferencedNames; } void setReferencedNameTracker(ReferencedNameTracker *Tracker) { diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index 34e2b8759399c..9f26c6c52a646 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -296,7 +296,6 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance { /// applies to the substituted type. ProtocolConformance *subst(ModuleDecl *module, Type substType, - ArrayRef subs, TypeSubstitutionMap &subMap, ArchetypeConformanceMap &conformanceMap); }; diff --git a/include/swift/AST/Requirement.h b/include/swift/AST/Requirement.h index 157cbc4ef45fa..63f87986af44f 100644 --- a/include/swift/AST/Requirement.h +++ b/include/swift/AST/Requirement.h @@ -74,6 +74,8 @@ class Requirement { Type getSecondType() const { return SecondType; } + + void dump() const; }; } // end namespace swift diff --git a/include/swift/AST/Substitution.h b/include/swift/AST/Substitution.h index c5c0717761363..9ba7f21fd316c 100644 --- a/include/swift/AST/Substitution.h +++ b/include/swift/AST/Substitution.h @@ -71,13 +71,12 @@ class Substitution { GenericEnvironment *env, ArrayRef subs) const; -private: - friend class ProtocolConformance; - Substitution subst(ModuleDecl *module, - ArrayRef subs, TypeSubstitutionMap &subMap, ArchetypeConformanceMap &conformanceMap) const; + +private: + friend class ProtocolConformance; }; void dump(const ArrayRef &subs); diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index e1198311934f6..8a42970ced1c3 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -636,6 +636,19 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// a type's subclass. bool isExactSuperclassOf(Type ty, LazyResolver *resolver); + /// \brief Get the substituted base class type, starting from a base class + /// declaration and a substituted derived class type. + /// + /// For example, given the following declarations: + /// + /// class A {} + /// class B : A {} + /// class C : B {} + /// + /// Calling `C`->getSuperclassForDecl(`A`) will return + /// `A`. + Type getSuperclassForDecl(const ClassDecl *classDecl, LazyResolver *resolver); + /// \brief True if this type is the superclass of another type, or a generic /// type that could be bound to the superclass. /// diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index cbc9c358e093d..b07e718241a94 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -503,7 +503,7 @@ class SILModule { lookUpWitnessTable(const ProtocolConformance *C, bool deserializeLazily=true); /// Attempt to lookup \p Member in the witness table for \p C. - std::tuple> + std::pair lookUpFunctionInWitnessTable(ProtocolConformanceRef C, SILDeclRef Requirement); diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 687ab87058546..86ac556dd4b8e 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -13,7 +13,6 @@ #ifndef SIL_TypeLowering_h #define SIL_TypeLowering_h -#include "swift/AST/ArchetypeBuilder.h" #include "swift/AST/CaptureInfo.h" #include "swift/ABI/MetadataValues.h" #include "swift/SIL/AbstractionPattern.h" diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d031d6e789af5..bdedf24682d42 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1450,7 +1450,7 @@ ArchetypeBuilder *ASTContext::getOrCreateArchetypeBuilder( // Create a new archetype builder with the given signature. auto builder = new ArchetypeBuilder(*mod, Diags); - builder->addGenericSignature(sig, /*adoptArchetypes=*/false, + builder->addGenericSignature(sig, nullptr, /*treatRequirementsAsExplicit=*/true); // Store this archetype builder. @@ -1459,15 +1459,6 @@ ArchetypeBuilder *ASTContext::getOrCreateArchetypeBuilder( return builder; } -void ASTContext::setArchetypeBuilder(CanGenericSignature sig, - ModuleDecl *mod, - std::unique_ptr builder) { - if (Impl.ArchetypeBuilders.find({sig, mod}) - == Impl.ArchetypeBuilders.end()) { - Impl.ArchetypeBuilders[{sig, mod}] = move(builder); - } -} - Module * ASTContext::getModule(ArrayRef> ModulePath) { assert(!ModulePath.empty()); @@ -3709,6 +3700,11 @@ GenericSignature *GenericSignature::get(ArrayRef params, bool isKnownCanonical) { assert(!params.empty()); +#ifndef NDEBUG + for (auto req : requirements) + assert(req.getFirstType()->isTypeParameter()); +#endif + // Check for an existing generic signature. llvm::FoldingSetNodeID ID; GenericSignature::Profile(ID, params, requirements); diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 07152c6c6aede..f9595e7c81ced 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ForeignErrorConvention.h" +#include "swift/AST/GenericEnvironment.h" #include "swift/AST/ParameterList.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/STLExtras.h" @@ -3092,3 +3093,11 @@ void TypeBase::dump(raw_ostream &os, unsigned indent) const { llvm::SaveAndRestore X(ctx.LangOpts.DebugConstraintSolver, true); Type(const_cast(this)).dump(os, indent); } + +void GenericEnvironment::dump() const { + llvm::errs() << "Generic environment:\n"; + for (auto pair : getInterfaceToArchetypeMap()) { + pair.first->dump(); + pair.second->dump(); + } +} diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 5d8c62df65a67..145bb0112a833 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -4383,6 +4383,27 @@ void GenericSignature::dump() const { llvm::errs() << '\n'; } +void Requirement::dump() const { + switch (getKind()) { + case RequirementKind::WitnessMarker: + llvm::errs() << "witness_marker: "; + break; + case RequirementKind::Conformance: + llvm::errs() << "conforms_to: "; + break; + case RequirementKind::Superclass: + llvm::errs() << "superclass: "; + break; + case RequirementKind::SameType: + llvm::errs() << "same_type: "; + break; + } + + if (getFirstType()) llvm::errs() << getFirstType() << " "; + if (getSecondType()) llvm::errs() << getSecondType(); + llvm::errs() << "\n"; +} + std::string GenericSignature::getAsString() const { std::string result; llvm::raw_string_ostream out(result); diff --git a/lib/AST/ArchetypeBuilder.cpp b/lib/AST/ArchetypeBuilder.cpp index f21f4e60dcc50..20a6077f46505 100644 --- a/lib/AST/ArchetypeBuilder.cpp +++ b/lib/AST/ArchetypeBuilder.cpp @@ -75,61 +75,14 @@ void RequirementSource::dump(llvm::raw_ostream &out, /// Update the recorded requirement source when a new requirement /// source provides the same requirement. static void updateRequirementSource(RequirementSource &source, - const RequirementSource &newSource) { - switch (newSource.getKind()) { - case RequirementSource::Explicit: - case RequirementSource::Redundant: - // Nothing to do; the new source is always redundant. - switch (source.getKind()) { - case RequirementSource::Explicit: - case RequirementSource::Redundant: - // Nothing to do. - break; - - case RequirementSource::Inferred: - case RequirementSource::Protocol: - // Mark the original source as redundant. - source = RequirementSource(RequirementSource::Redundant, - newSource.getLoc()); - break; - - case RequirementSource::OuterScope: - // Leave the outer scope in place. - break; - } - break; - - case RequirementSource::Inferred: - // A new inferred source will never override an existing source. - break; - - case RequirementSource::Protocol: { - switch (source.getKind()) { - case RequirementSource::Explicit: - case RequirementSource::Redundant: - // The original source is redundant. - source.setKind(RequirementSource::Redundant); - break; - - case RequirementSource::Protocol: - case RequirementSource::OuterScope: - // Keep the original source. - break; - - case RequirementSource::Inferred: - // Replace the inferred source with the protocol source. - source = newSource; - break; - } - - break; - } - - case RequirementSource::OuterScope: - // An outer-scope source always overrides an existing source. + RequirementSource newSource) { + // If the new source is less explicit than the existing source, + // or if they have the same kind but we don't have source location + // information yet, replace the existing source. + if (source.getKind() < newSource.getKind() || + (source.getKind() == newSource.getKind() && + !source.getLoc().isValid())) source = newSource; - break; - } } /// The identifying information for a generic parameter. @@ -170,10 +123,6 @@ struct ArchetypeBuilder::Implementation { /// archetypes. llvm::MapVector PotentialArchetypes; - /// A vector containing the same-type requirements introduced into the - /// system. - SmallVector SameTypeRequirements; - /// The number of nested types that haven't yet been resolved to archetypes. /// Once all requirements have been added, this will be zero in well-formed /// code. @@ -245,6 +194,7 @@ void ArchetypeBuilder::PotentialArchetype::resolveAssociatedType( assert(!NameOrAssociatedType.is() && "associated type is already resolved"); NameOrAssociatedType = assocType; + assert(assocType->getName() == getName()); assert(builder.Impl->NumUnresolvedNestedTypes > 0 && "Mismatch in number of unresolved nested types"); --builder.Impl->NumUnresolvedNestedTypes; @@ -282,7 +232,7 @@ static ProtocolConformance *getSuperConformance( // appropriately. updateRequirementSource( conformsSource, - RequirementSource(RequirementSource::Protocol, + RequirementSource(RequirementSource::Redundant, pa->getSuperclassSource().getLoc())); return conformance->getConcrete(); } @@ -307,13 +257,14 @@ static void maybeAddSameTypeRequirementForNestedType( if (!concreteType) return; // Add the same-type constraint. - RequirementSource source(RequirementSource::Protocol, fromSource.getLoc()); concreteType = ArchetypeBuilder::mapTypeOutOfContext( superConformance->getDeclContext(), concreteType); if (auto otherPA = builder.resolveArchetype(concreteType)) - builder.addSameTypeRequirementBetweenArchetypes(nestedPA, otherPA, source); + builder.addSameTypeRequirementBetweenArchetypes( + nestedPA, otherPA, fromSource); else - builder.addSameTypeRequirementToConcrete(nestedPA, concreteType, source); + builder.addSameTypeRequirementToConcrete( + nestedPA, concreteType, fromSource); } bool ArchetypeBuilder::PotentialArchetype::addConformance( @@ -342,6 +293,9 @@ bool ArchetypeBuilder::PotentialArchetype::addConformance( inserted->second, builder); + RequirementSource redundantSource(RequirementSource::Redundant, + source.getLoc()); + // Check whether any associated types in this protocol resolve // nested types of this potential archetype. for (auto member : proto->getMembers()) { @@ -360,7 +314,8 @@ bool ArchetypeBuilder::PotentialArchetype::addConformance( // If there's a superclass constraint that conforms to the protocol, // add the appropriate same-type relationship. maybeAddSameTypeRequirementForNestedType(known->second.front(), - source, superConformance, + redundantSource, + superConformance, builder); continue; } @@ -371,13 +326,12 @@ bool ArchetypeBuilder::PotentialArchetype::addConformance( auto frontRep = known->second.front()->getRepresentative(); otherPA->Representative = frontRep; frontRep->EquivalenceClass.push_back(otherPA); - otherPA->SameTypeSource = RequirementSource(RequirementSource::Inferred, - source.getLoc()); + otherPA->SameTypeSource = redundantSource; known->second.push_back(otherPA); // If there's a superclass constraint that conforms to the protocol, // add the appropriate same-type relationship. - maybeAddSameTypeRequirementForNestedType(otherPA, source, + maybeAddSameTypeRequirementForNestedType(otherPA, redundantSource, superConformance, builder); } @@ -413,7 +367,7 @@ bool ArchetypeBuilder::PotentialArchetype::hasConcreteTypeInPath() const { } bool ArchetypeBuilder::PotentialArchetype::isBetterArchetypeAnchor( - PotentialArchetype *other) { + PotentialArchetype *other) const { auto concrete = hasConcreteTypeInPath(); auto otherConcrete = other->hasConcreteTypeInPath(); if (concrete != otherConcrete) @@ -430,14 +384,15 @@ bool ArchetypeBuilder::PotentialArchetype::isBetterArchetypeAnchor( auto ArchetypeBuilder::PotentialArchetype::getArchetypeAnchor() -> PotentialArchetype * { - // Default to the representative, unless we find something better. - PotentialArchetype *best = getRepresentative(); - for (auto pa : getEquivalenceClass()) { - if (pa->isBetterArchetypeAnchor(best)) - best = pa; - } - - return best; + + // Default to the representative, unless we find something better. + PotentialArchetype *best = getRepresentative(); + for (auto pa : best->getEquivalenceClass()) { + if (pa->isBetterArchetypeAnchor(best)) + best = pa; + } + + return best; } auto ArchetypeBuilder::PotentialArchetype::getNestedType( @@ -452,6 +407,9 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType( return NestedTypes[nestedName].front(); } + RequirementSource redundantSource(RequirementSource::Redundant, + SourceLoc()); + // Attempt to resolve this nested type to an associated type // of one of the protocols to which the parent potential // archetype conforms. @@ -510,8 +468,8 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType( } if (pa != existingPA) { pa->Representative = existingPA; - RequirementSource source(RequirementSource::Inferred, SourceLoc()); - pa->SameTypeSource = source; + pa->Representative->EquivalenceClass.push_back(pa); + pa->SameTypeSource = redundantSource; } } else if (type->hasArchetype()) { // This is a complex type involving other associatedtypes, we'll fail @@ -519,13 +477,13 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType( continue; } else { pa->ArchetypeOrConcreteType = NestedType::forConcreteType(type); + pa->SameTypeSource = redundantSource; } } else continue; // If we have resolved this nested type to more than one associated // type, create same-type constraints between them. - RequirementSource source(RequirementSource::Inferred, SourceLoc()); llvm::TinyPtrVector &nested = NestedTypes[nestedName]; if (!nested.empty()) { @@ -540,14 +498,14 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType( for (auto existing : nested) { existing->Representative = pa; existing->Representative->EquivalenceClass.push_back(existing); - existing->SameTypeSource = source; + existing->SameTypeSource = redundantSource; } nested.insert(nested.begin(), pa); NestedTypes[nestedName] = nested; } else { pa->Representative = existing->getRepresentative(); pa->Representative->EquivalenceClass.push_back(pa); - pa->SameTypeSource = source; + pa->SameTypeSource = redundantSource; nested.push_back(pa); } } else @@ -557,7 +515,7 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType( // add the appropriate same-type relationship. ProtocolConformance *superConformance = getSuperConformance(this, conforms.first, conforms.second, builder); - maybeAddSameTypeRequirementForNestedType(pa, source, + maybeAddSameTypeRequirementForNestedType(pa, redundantSource, superConformance, builder); } } @@ -595,9 +553,12 @@ static Type substConcreteTypesForDependentTypes(ArchetypeBuilder &builder, ArchetypeType::NestedType ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) { + auto representative = getRepresentative(); // Retrieve the archetype from the archetype anchor in this equivalence class. + // The anchor must not have any concrete parents (otherwise we would just + // use the representative). auto archetypeAnchor = getArchetypeAnchor(); if (archetypeAnchor != this) return archetypeAnchor->getType(builder); @@ -701,6 +662,7 @@ ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) { representative->ArchetypeOrConcreteType = NestedType::forConcreteType( builder.substDependentType(memberType)); + representative->SameTypeSource = parent->SameTypeSource; return representative->ArchetypeOrConcreteType; } @@ -956,7 +918,7 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT, if (!T->addConformance(Proto, Source, *this)) return false; - RequirementSource InnerSource(RequirementSource::Protocol, Source.getLoc()); + RequirementSource InnerSource(RequirementSource::Redundant, Source.getLoc()); bool inserted = Visited.insert(Proto).second; assert(inserted); @@ -1028,10 +990,13 @@ bool ArchetypeBuilder::addSuperclassRequirement(PotentialArchetype *T, auto nested = nestedTypes.find(assocType->getName()); if (nested == nestedTypes.end()) continue; + RequirementSource redundantSource(RequirementSource::Redundant, + Source.getLoc()); + for (auto nestedPA : nested->second) { if (nestedPA->getResolvedAssociatedType() == assocType) maybeAddSameTypeRequirementForNestedType(nestedPA, - Source, + redundantSource, superConformance, *this); } } @@ -1088,13 +1053,80 @@ bool ArchetypeBuilder::addSuperclassRequirement(PotentialArchetype *T, return false; } +/// Canonical ordering for dependent types in generic signatures. +static int compareDependentTypes(ArchetypeBuilder::PotentialArchetype * const* pa, + ArchetypeBuilder::PotentialArchetype * const* pb) { + auto a = *pa, b = *pb; + + // Fast-path check for equality. + if (a == b) + return 0; + + // Ordering is as follows: + // - Generic params + if (auto gpa = a->getGenericParam()) { + if (auto gpb = b->getGenericParam()) { + // - by depth, so t_0_n < t_1_m + if (int compareDepth = gpa->getDepth() - gpb->getDepth()) + return compareDepth; + // - by index, so t_n_0 < t_n_1 + if (int compareIndex = gpa->getIndex() - gpb->getIndex()) + return compareIndex; + llvm_unreachable("total order failure among generic parameters"); + } + + // A generic param is always ordered before a nested type. + return -1; + } + + if (b->getGenericParam()) + return +1; + + // - Dependent members + auto ppa = a->getParent(); + auto ppb = b->getParent(); + + // - by base, so t_0_n.`P.T` < t_1_m.`P.T` + if (int compareBases = compareDependentTypes(&ppa, &ppb)) + return compareBases; + + // - by name, so t_n_m.`P.T` < t_n_m.`P.U` + if (int compareNames = a->getName().str().compare(b->getName().str())) + return compareNames; + + if (auto *aa = a->getResolvedAssociatedType()) { + if (auto *ab = b->getResolvedAssociatedType()) { + // - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q) + auto protoa = aa->getProtocol(); + auto protob = ab->getProtocol(); + if (int compareProtocols + = ProtocolType::compareProtocols(&protoa, &protob)) + return compareProtocols; + + // - if one is the representative, put it first. + if ((a->getRepresentative() == a) != + (b->getRepresentative() == b)) + return a->getRepresentative() ? -1 : 1; + + // FIXME: Would be nice if this was a total order. + return 0; + } + + // A resolved archetype is always ordered before an unresolved one. + return -1; + } + + if (b->getResolvedAssociatedType()) + return +1; + + llvm_unreachable("potential archetype total order failure"); +} + bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes( PotentialArchetype *T1, PotentialArchetype *T2, RequirementSource Source) { - auto OrigT1 = T1, OrigT2 = T2; - // Operate on the representatives T1 = T1->getRepresentative(); T2 = T2->getRepresentative(); @@ -1107,15 +1139,20 @@ bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes( // We necessarily prefer potential archetypes rooted at parameters that come // from outer generic parameter lists, since those generic parameters will // have archetypes bound in the outer context. - // FIXME: This isn't a total ordering + // + // FIXME: The above comment is mostly obsolete, so why can't we just use + // compareDependentTypes() here? auto T1Param = T1->getRootParam(); auto T2Param = T2->getRootParam(); unsigned T1Depth = T1->getNestingDepth(); unsigned T2Depth = T2->getNestingDepth(); - if (std::make_tuple(T2->wasRenamed(), T2Param->getDepth(), - T2Param->getIndex(), T2Depth) - < std::make_tuple(T1->wasRenamed(), T1Param->getDepth(), - T1Param->getIndex(), T1Depth)) + auto T1Key = std::make_tuple(T1->wasRenamed(), T1Param->getDepth(), + T1Param->getIndex(), T1Depth); + auto T2Key = std::make_tuple(T2->wasRenamed(), T2Param->getDepth(), + T2Param->getIndex(), T2Depth); + if (T2Key < T1Key || + (T2Key == T1Key && + compareDependentTypes(&T2, &T1) < 0)) std::swap(T1, T2); // Don't allow two generic parameters to be equivalent, because then we @@ -1156,11 +1193,6 @@ bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes( for (auto equiv : T2->EquivalenceClass) T1->EquivalenceClass.push_back(equiv); - if (!T1->wasRenamed() && !T2->wasRenamed()) { - // Record this same-type requirement. - Impl->SameTypeRequirements.push_back({ OrigT1, OrigT2 }); - } - // FIXME: superclass requirements! // Add all of the protocol conformance requirements of T2 to T1. @@ -1169,12 +1201,12 @@ bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes( } // Recursively merge the associated types of T2 into T1. - RequirementSource inferredSource(RequirementSource::Inferred, SourceLoc()); + RequirementSource redundantSource(RequirementSource::Redundant, SourceLoc()); for (auto T2Nested : T2->NestedTypes) { auto T1Nested = T1->getNestedType(T2Nested.first, *this); if (addSameTypeRequirementBetweenArchetypes(T1Nested, T2Nested.second.front(), - inferredSource)) + redundantSource)) return true; } @@ -1186,7 +1218,6 @@ bool ArchetypeBuilder::addSameTypeRequirementToConcrete( Type Concrete, RequirementSource Source) { // Operate on the representative. - auto OrigT = T; T = T->getRepresentative(); assert(!T->ArchetypeOrConcreteType.getAsArchetype() @@ -1236,8 +1267,6 @@ bool ArchetypeBuilder::addSameTypeRequirementToConcrete( T->ArchetypeOrConcreteType = NestedType::forConcreteType(Concrete); T->SameTypeSource = Source; - Impl->SameTypeRequirements.push_back({OrigT, Concrete}); - // Recursively resolve the associated types to their concrete types. for (auto nested : T->getNestedTypes()) { AssociatedTypeDecl *assocType @@ -1744,7 +1773,7 @@ bool ArchetypeBuilder::finalize(SourceLoc loc) { auto replacement = pa->getParent()->getNestedType(correction, *this); addSameTypeRequirementBetweenArchetypes( pa, replacement, - RequirementSource(RequirementSource::Inferred, SourceLoc())); + RequirementSource(RequirementSource::Redundant, SourceLoc())); }); } @@ -1761,11 +1790,6 @@ ArchetypeBuilder::getArchetype(GenericTypeParamDecl *GenericParam) { return known->second->getType(*this).getAsArchetype(); } -ArrayRef -ArchetypeBuilder::getSameTypeRequirements() const { - return Impl->SameTypeRequirements; -} - template void ArchetypeBuilder::visitPotentialArchetypes(F f) { // Stack containing all of the potential archetypes to visit. @@ -1795,65 +1819,54 @@ void ArchetypeBuilder::visitPotentialArchetypes(F f) { } } -namespace { - /// \brief Function object that orders potential archetypes by name. - struct OrderPotentialArchetypeByName { - using PotentialArchetype = ArchetypeBuilder::PotentialArchetype; - - bool operator()(std::pair X, - std::pair Y) const { - return X.first.str() < Y.second->getName().str(); - } - - bool operator()(std::pair X, - Identifier Y) const { - return X.first.str() < Y.str(); - } - - bool operator()(Identifier X, - std::pair Y) const { - return X.str() < Y.first.str(); - } - - bool operator()(Identifier X, Identifier Y) const { - return X.str() < Y.str(); - } - }; -} - void ArchetypeBuilder::enumerateRequirements(llvm::function_ref< void (RequirementKind kind, PotentialArchetype *archetype, llvm::PointerUnion type, RequirementSource source)> f) { - // Local function to visit a potential archetype, enumerating its - // requirements. - auto visitPA = [&](PotentialArchetype *archetype) { + // First, collect all archetypes, and sort them. + SmallVector archetypes; + visitPotentialArchetypes([&](PotentialArchetype *archetype) { + archetypes.push_back(archetype); + }); + + llvm::array_pod_sort(archetypes.begin(), archetypes.end(), + compareDependentTypes); + + for (auto *archetype : archetypes) { // Invalid archetypes are never representatives in well-formed or corrected // signature, so we don't need to visit them. if (archetype->isInvalid()) - return; + continue; - // If this is not the representative, produce a same-type - // constraint to the representative. - if (archetype->getRepresentative() != archetype) { - if (!archetype->wasRenamed()) - f(RequirementKind::SameType, archetype, archetype->getRepresentative(), - archetype->getSameTypeSource()); - return; - } + // If this type is not the representative, or if it was made concrete, + // we emit a same-type constraint. + if (archetype->getRepresentative() != archetype || + archetype->isConcreteType()) { + auto *first = archetype; + auto *second = archetype->getRepresentative(); + + if (second->isConcreteType()) { + Type concreteType = second->getConcreteType(); + f(RequirementKind::SameType, first, concreteType, + first->getSameTypeSource()); + continue; + } + + assert(!first->isConcreteType()); - // If we have a concrete type, produce a same-type requirement. - if (archetype->isConcreteType()) { - Type concreteType = archetype->getConcreteType(); - f(RequirementKind::SameType, archetype, concreteType, + // Neither one is concrete. Put the shorter type first. + if (compareDependentTypes(&first, &second) > 0) + std::swap(first, second); + + f(RequirementKind::SameType, first, second, archetype->getSameTypeSource()); - return; + continue; } // Add the witness marker. f(RequirementKind::WitnessMarker, archetype, Type(), - RequirementSource(RequirementSource::Protocol, SourceLoc())); + RequirementSource(RequirementSource::Explicit, SourceLoc())); // If we have a superclass, produce a superclass requirement if (Type superclass = archetype->getSuperclass()) { @@ -1883,51 +1896,6 @@ void ArchetypeBuilder::enumerateRequirements(llvm::function_ref< protocolSources.find(proto)->second); } }; - - // Local function to visit the nested potential archetypes of the - // given potential archetype. - std::function visitNested - = [&](PotentialArchetype *archetype) { - // Collect the nested types, sorted by name. - SmallVector, 16> nestedTypes; - for (const auto &nested : archetype->getNestedTypes()) { - for (auto nestedPA : nested.second) - nestedTypes.push_back(std::make_pair(nested.first, nestedPA)); - } - std::stable_sort(nestedTypes.begin(), nestedTypes.end(), - OrderPotentialArchetypeByName()); - - // Add requirements for the nested types. - for (const auto &nested : nestedTypes) { - visitPA(nested.second); - visitNested(nested.second); - } - }; - - auto primaryIter = Impl->PotentialArchetypes.begin(), - primaryIterEnd = Impl->PotentialArchetypes.end(); - while (primaryIter != primaryIterEnd) { - unsigned depth = primaryIter->first.Depth; - - // For each of the primary potential archetypes, add the requirements. - // Stop when we hit a parameter at a different depth. - // FIXME: This algorithm falls out from the way the "all archetypes" lists - // are structured. Once those lists no longer exist or are no longer - // "the truth", we can simplify this algorithm considerably. - auto nextPrimaryIter = primaryIter; - for (/*none*/; - (nextPrimaryIter != primaryIterEnd && - nextPrimaryIter->first.Depth == depth); - ++nextPrimaryIter) { - visitPA(nextPrimaryIter->second); - } - - // For each of the primary potential archetypes, add the nested - // requirements. - for (; primaryIter != nextPrimaryIter; ++primaryIter) { - visitNested(primaryIter->second); - } - } } void ArchetypeBuilder::dump() { @@ -1936,7 +1904,7 @@ void ArchetypeBuilder::dump() { void ArchetypeBuilder::dump(llvm::raw_ostream &out) { out << "Requirements:"; - enumerateRequirements([&](RequirementKind kind, + enumerateRequirements([&](RequirementKind kind, PotentialArchetype *archetype, llvm::PointerUnion type, RequirementSource source) { @@ -2012,7 +1980,7 @@ ArchetypeBuilder::mapTypeOutOfContext(ModuleDecl *M, } void ArchetypeBuilder::addGenericSignature(GenericSignature *sig, - bool adoptArchetypes, + GenericEnvironment *env, bool treatRequirementsAsExplicit) { if (!sig) return; @@ -2023,21 +1991,17 @@ void ArchetypeBuilder::addGenericSignature(GenericSignature *sig, for (auto param : sig->getGenericParams()) { addGenericParameter(param); - if (adoptArchetypes) { + if (env) { // If this generic parameter has an archetype, use it as the concrete // type. - // FIXME: This forces us to re-use archetypes from outer scopes as - // concrete types, which is currently important for the layout of the "all - // archetypes" list. - if (auto gpDecl = param->getDecl()) { - if (auto archetype = gpDecl->getArchetype()) { - auto key = GenericTypeParamKey::forDecl(gpDecl); - assert(Impl->PotentialArchetypes.count(key) && "Missing parameter?"); - auto *pa = Impl->PotentialArchetypes[key]; - assert(pa == pa->getRepresentative() && "Not the representative"); - pa->ArchetypeOrConcreteType = NestedType::forConcreteType(archetype); - pa->SameTypeSource = RequirementSource(sourceKind, SourceLoc()); - } + auto contextTy = env->mapTypeIntoContext(&Mod, param); + if (auto archetype = contextTy->getAs()) { + auto key = GenericTypeParamKey::forType(param); + assert(Impl->PotentialArchetypes.count(key) && "Missing parameter?"); + auto *pa = Impl->PotentialArchetypes[key]; + assert(pa == pa->getRepresentative() && "Not the representative"); + pa->ArchetypeOrConcreteType = NestedType::forConcreteType(archetype); + pa->SameTypeSource = RequirementSource(sourceKind, SourceLoc()); } } } @@ -2052,166 +2016,54 @@ Type ArchetypeBuilder::substDependentType(Type type) { return substConcreteTypesForDependentTypes(*this, type); } -/// Add the requirements for the given potential archetype and its nested -/// potential archetypes to the set of requirements. -static void -addRequirements( - ArchetypeBuilder &builder, Type type, - ArchetypeBuilder::PotentialArchetype *pa, - llvm::SmallPtrSet &knownPAs, - SmallVectorImpl &requirements) { - - auto &ctx = builder.getASTContext(); - - // If the potential archetype has been bound away to a concrete type, - // it needs no requirements. - if (pa->isConcreteType()) - return; - - // Add a value witness marker. - requirements.push_back(Requirement(RequirementKind::WitnessMarker, - type, Type())); - - // Add superclass requirement, if needed. - if (auto superclass = pa->getSuperclass()) { - // FIXME: What if the superclass type involves a type parameter? - requirements.push_back(Requirement(RequirementKind::Superclass, - type, superclass)); - } - - // Add conformance requirements. - SmallVector protocols; - for (const auto &conforms : pa->getConformsTo()) { - protocols.push_back(conforms.first); - } - - ProtocolType::canonicalizeProtocols(protocols); - for (auto proto : protocols) { - requirements.push_back(Requirement(RequirementKind::Conformance, type, - ProtocolType::get(proto, ctx))); - } -} - -static void -addNestedRequirements( - ArchetypeBuilder &builder, - ArchetypeBuilder::PotentialArchetype *pa, - llvm::SmallPtrSet &knownPAs, - SmallVectorImpl &requirements) { - using PotentialArchetype = ArchetypeBuilder::PotentialArchetype; - - // Collect the nested types, sorted by name. - // FIXME: Could collect these from the conformance requirements, above. - SmallVector, 16> nestedTypes; - for (const auto &nested : pa->getNestedTypes()) { - // FIXME: Dropping requirements among different associated types of the - // same name. - // Skip type aliases, which are just shortcuts down the tree. - if (nested.second.front()->getTypeAliasDecl()) - continue; - nestedTypes.push_back(std::make_pair(nested.first, nested.second.front())); - } - std::sort(nestedTypes.begin(), nestedTypes.end(), - OrderPotentialArchetypeByName()); - - // Add requirements for associated types. - for (const auto &nested : nestedTypes) { - auto rep = nested.second->getRepresentative(); - if (knownPAs.insert(rep).second) { - // Form the dependent type that refers to this archetype. - auto assocType = nested.second->getResolvedAssociatedType(); - if (!assocType) - continue; // FIXME: If we do this late enough, there will be no failure. - - // Skip nested types bound to concrete types. - if (rep->isConcreteType()) - continue; - - auto nestedType = - rep->getDependentType(builder, /*allowUnresolved*/ false); - - // Skip unresolved nested types. - if (nestedType->is()) - continue; - - addRequirements(builder, nestedType, rep, knownPAs, requirements); - addNestedRequirements(builder, rep, knownPAs, requirements); - } - } -} - - /// Collect the set of requirements placed on the given generic parameters and /// their associated types. static void collectRequirements(ArchetypeBuilder &builder, ArrayRef params, SmallVectorImpl &requirements) { - typedef ArchetypeBuilder::PotentialArchetype PotentialArchetype; + builder.enumerateRequirements([&](RequirementKind kind, + ArchetypeBuilder::PotentialArchetype *archetype, + llvm::PointerUnion type, + RequirementSource source) { + // Filter out redundant requirements. + switch (source.getKind()) { + case RequirementSource::Explicit: + case RequirementSource::Inferred: + case RequirementSource::OuterScope: + // The requirement was explicit and required, keep it. + break; - // Find the "primary" potential archetypes, from which we'll collect all - // of the requirements. - llvm::SmallPtrSet knownPAs; - llvm::SmallVector primary; - for (auto param : params) { - auto pa = builder.resolveArchetype(param); - assert(pa && "Missing potential archetype for generic parameter"); + case RequirementSource::Protocol: + case RequirementSource::Redundant: + // The requirement was redundant, drop it. + return; + } - // We only care about the representative. - pa = pa->getRepresentative(); + auto depTy = archetype->getDependentType(builder, false); - if (knownPAs.insert(pa).second) - primary.push_back(param); - } + if (depTy->is()) + return; - // Add all of the conformance and superclass requirements placed on the given - // generic parameters and their associated types. - unsigned primaryIdx = 0, numPrimary = primary.size(); - while (primaryIdx < numPrimary) { - unsigned depth = primary[primaryIdx]->getDepth(); - - // For each of the primary potential archetypes, add the requirements. - // Stop when we hit a parameter at a different depth. - // FIXME: This algorithm falls out from the way the "all archetypes" lists - // are structured. Once those lists no longer exist or are no longer - // "the truth", we can simplify this algorithm considerably. - unsigned lastPrimaryIdx = primaryIdx; - for (unsigned idx = primaryIdx; - idx < numPrimary && primary[idx]->getDepth() == depth; - ++idx, ++lastPrimaryIdx) { - auto param = primary[idx]; - auto pa = builder.resolveArchetype(param)->getRepresentative(); - - // Add other requirements. - addRequirements(builder, param, pa, knownPAs, requirements); + if (kind == RequirementKind::WitnessMarker) { + requirements.push_back(Requirement(kind, depTy, Type())); + return; } - // For each of the primary potential archetypes, add the nested requirements. - for (unsigned idx = primaryIdx; idx < lastPrimaryIdx; ++idx) { - auto param = primary[idx]; - auto pa = builder.resolveArchetype(param)->getRepresentative(); - addNestedRequirements(builder, pa, knownPAs, requirements); + Type repTy; + if (auto concreteTy = type.dyn_cast()) { + // Maybe we were equated to a concrete type... + repTy = concreteTy; + } else { + // ...or to a dependent type. + repTy = type.get() + ->getDependentType(builder, false); } - primaryIdx = lastPrimaryIdx; - } - - - // Add all of the same-type requirements. - for (auto req : builder.getSameTypeRequirements()) { - auto firstType = req.first->getDependentType(builder, false); - Type secondType; - if (auto concrete = req.second.dyn_cast()) - secondType = concrete; - else if (auto secondPA = req.second.dyn_cast()) - secondType = secondPA->getDependentType(builder, false); - - if (firstType->is() || secondType->is() || - firstType->isEqual(secondType)) - continue; + if (repTy->is()) + return; - requirements.push_back(Requirement(RequirementKind::SameType, - firstType, secondType)); - } + requirements.push_back(Requirement(kind, depTy, repTy)); + }); } GenericSignature *ArchetypeBuilder::getGenericSignature( diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index e13b02c7c284d..416841163c5e8 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -1,4 +1,4 @@ -//===--- GenericEnvironment.h - GenericEnvironment AST --------------------===// +//===--- GenericEnvironment.cpp - GenericEnvironment AST ------------------===// // // This source file is part of the Swift.org open source project // @@ -69,7 +69,7 @@ ArrayRef GenericEnvironment::getForwardingSubstitutions( ModuleDecl *M, GenericSignature *sig) const { auto lookupConformanceFn = - [&](Type replacement, ProtocolType *protoType) + [&](CanType original, Type replacement, ProtocolType *protoType) -> ProtocolConformanceRef { return ProtocolConformanceRef(protoType->getDecl()); }; diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index b3d85ae513b2a..f50565de376cc 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -136,250 +136,6 @@ GenericSignature::getCanonicalSignature() const { CanonicalSignatureOrASTContext.get()); } -/// Canonical ordering for dependent types in generic signatures. -static int compareDependentTypes(const CanType *pa, const CanType *pb) { - auto a = *pa, b = *pb; - - // Fast-path check for equality. - if (a == b) - return 0; - - // Ordering is as follows: - // - Generic params - if (auto gpa = dyn_cast(a)) { - if (auto gpb = dyn_cast(b)) { - // - by depth, so t_0_n < t_1_m - if (int compareDepth = gpa->getDepth() - gpb->getDepth()) - return compareDepth; - // - by index, so t_n_0 < t_n_1 - return gpa->getIndex() - gpb->getIndex(); - } - return -1; - } - - // - Dependent members - if (auto dma = dyn_cast(a)) { - if (isa(b)) - return +1; - if (auto dmb = dyn_cast(b)) { - // - by base, so t_0_n.`P.T` < t_1_m.`P.T` - auto abase = dma.getBase(); - auto bbase = dmb.getBase(); - if (int compareBases = compareDependentTypes(&abase, &bbase)) - return compareBases; - - // - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q) - auto protoa = dma->getAssocType()->getProtocol(); - auto protob = dmb->getAssocType()->getProtocol(); - if (int compareProtocols - = ProtocolType::compareProtocols(&protoa, &protob)) - return compareProtocols; - - // - by name, so t_n_m.`P.T` < t_n_m.`P.U` - return dma->getAssocType()->getName().str().compare( - dmb->getAssocType()->getName().str()); - } - return -1; - } - - // - Other types. - // - // There should only ever be one of these in a set of constraints related to - // a dependent type, so the ordering among other types does not matter. - if (isa(b) || isa(b)) - return +1; - return 0; -} - -CanGenericSignature -GenericSignature::getCanonicalManglingSignature(ModuleDecl &M) const { - // Start from the elementwise-canonical signature. - auto canonical = getCanonicalSignature(); - auto &Context = canonical->getASTContext(); - - // See if we cached the mangling signature. - auto cached = Context.ManglingSignatures.find({canonical, &M}); - if (cached != Context.ManglingSignatures.end()) { - return cached->second; - } - - // Otherwise, we need to compute it. - // Dump the generic signature into an ArchetypeBuilder that will figure out - // the minimal set of requirements. - std::unique_ptr builder(new ArchetypeBuilder(M, - Context.Diags)); - - builder->addGenericSignature(canonical, /*adoptArchetypes*/ false, - /*treatRequirementsAsExplicit*/ true); - - // Sort out the requirements. - struct DependentConstraints { - CanType baseClass; - SmallVector protocols; - }; - - SmallVector depTypes; - llvm::DenseMap constraints; - llvm::DenseMap> sameTypes; - - builder->enumerateRequirements([&](RequirementKind kind, - ArchetypeBuilder::PotentialArchetype *archetype, - llvm::PointerUnion type, - RequirementSource source) { - CanType depTy - = archetype->getDependentType(*builder, false)->getCanonicalType(); - - // Filter out redundant requirements. - switch (source.getKind()) { - case RequirementSource::Explicit: - // The requirement was explicit and required, keep it. - break; - - case RequirementSource::Protocol: - // Keep witness markers. - if (kind == RequirementKind::WitnessMarker) - break; - return; - - case RequirementSource::Redundant: - case RequirementSource::Inferred: - // The requirement was inferred or redundant, drop it. - return; - - case RequirementSource::OuterScope: - llvm_unreachable("shouldn't have an outer scope!"); - } - - switch (kind) { - case RequirementKind::WitnessMarker: { - // Introduce the dependent type into the constraint set, to ensure we - // have a record for every dependent type. - depTypes.push_back(depTy); - return; - } - - case RequirementKind::Superclass: { - assert(std::find(depTypes.begin(), depTypes.end(), - depTy) != depTypes.end() - && "didn't see witness marker first?"); - // Organize conformance constraints, sifting out the base class - // requirement. - auto &depConstraints = constraints[depTy]; - - auto constraintType = type.get()->getCanonicalType(); - assert(depConstraints.baseClass.isNull() - && "multiple base class constraints?!"); - depConstraints.baseClass = constraintType; - return; - } - - case RequirementKind::Conformance: { - assert(std::find(depTypes.begin(), depTypes.end(), - depTy) != depTypes.end() - && "didn't see witness marker first?"); - // Organize conformance constraints, sifting out the base class - // requirement. - auto &depConstraints = constraints[depTy]; - - auto constraintType = type.get()->getCanonicalType(); - assert(constraintType->isExistentialType()); - depConstraints.protocols.push_back(constraintType); - return; - } - - case RequirementKind::SameType: - // Collect the same-type constraints by their representative. - CanType repTy; - if (auto concreteTy = type.dyn_cast()) { - // Maybe we were equated to a concrete type... - repTy = concreteTy->getCanonicalType(); - } else { - // ...or to a representative dependent type that was in turn equated - // to a concrete type. - auto representative - = type.get(); - - if (representative->isConcreteType()) - repTy = representative->getConcreteType()->getCanonicalType(); - else - repTy = representative->getDependentType(*builder, false) - ->getCanonicalType(); - } - - sameTypes[repTy].push_back(depTy); - return; - } - }); - - // Order the dependent types canonically. - llvm::array_pod_sort(depTypes.begin(), depTypes.end(), compareDependentTypes); - - // Build a new set of minimized requirements. - // Emit the conformance constraints. - SmallVector minimalRequirements; - for (auto depTy : depTypes) { - minimalRequirements.push_back(Requirement(RequirementKind::WitnessMarker, - depTy, Type())); - - auto foundConstraints = constraints.find(depTy); - if (foundConstraints != constraints.end()) { - const auto &depConstraints = foundConstraints->second; - - if (depConstraints.baseClass) - minimalRequirements.push_back(Requirement(RequirementKind::Superclass, - depTy, - depConstraints.baseClass)); - - for (auto protocol : depConstraints.protocols) - minimalRequirements.push_back(Requirement(RequirementKind::Conformance, - depTy, protocol)); - } - } - - // Collect the same type constraints. - unsigned sameTypeBegin = minimalRequirements.size(); - - for (auto &group : sameTypes) { - // Sort the types in the set. - auto types = std::move(group.second); - types.push_back(group.first); - llvm::array_pod_sort(types.begin(), types.end(), compareDependentTypes); - - // Form constraints with the greater type on the right (which will be the - // concrete type, if one). - auto rhsType = types.pop_back_val(); - for (auto lhsType : types) - minimalRequirements.push_back(Requirement(RequirementKind::SameType, - lhsType, rhsType)); - } - - // Sort the same-types by LHS, then by RHS. - std::sort(minimalRequirements.begin() + sameTypeBegin, minimalRequirements.end(), - [](const Requirement &a, const Requirement &b) -> bool { - assert(a.getKind() == b.getKind() - && a.getKind() == RequirementKind::SameType - && "not same type constraints"); - CanType aLHS(a.getFirstType()), bLHS(b.getFirstType()); - if (int compareLHS = compareDependentTypes(&aLHS, &bLHS)) - return compareLHS < 0; - CanType aRHS(a.getSecondType()), bRHS(b.getSecondType()); - return compareDependentTypes(&aRHS, &bRHS); - }); - - // Build the minimized signature. - auto manglingSig = GenericSignature::get(canonical->getGenericParams(), - minimalRequirements, - /*isKnownCanonical=*/true); - - CanGenericSignature canSig(manglingSig); - - // Cache the result. - Context.ManglingSignatures.insert({{canonical, &M}, canSig}); - Context.setArchetypeBuilder(canSig, &M, std::move(builder)); - - return canSig; -} - ASTContext &GenericSignature::getASTContext() const { // Canonical signatures store the ASTContext directly. if (auto ctx = CanonicalSignatureOrASTContext.dyn_cast()) @@ -390,49 +146,57 @@ ASTContext &GenericSignature::getASTContext() const { } TypeSubstitutionMap -GenericSignature::getSubstitutionMap(ArrayRef args) const { - TypeSubstitutionMap subs; - +GenericSignature::getSubstitutionMap(ArrayRef subs) const { + TypeSubstitutionMap subMap; + TypeConformanceMap conformanceMap; + + getSubstitutionMap(subs, subMap, conformanceMap); + + return subMap; +} + +void GenericSignature:: +getSubstitutionMap(ArrayRef subs, + TypeSubstitutionMap &subMap, + TypeConformanceMap &conformanceMap) const { + // An empty parameter list gives an empty map. - if (getGenericParams().empty()) { - assert(args.empty() && "substitutions but no generic params?!"); - return subs; + if (subs.empty()) { + assert(getGenericParams().empty()); + return; } - - // Seed the type map with pre-existing substitutions. + for (auto depTy : getAllDependentTypes()) { - auto replacement = args.front().getReplacement(); - args = args.slice(1); - - if (auto subTy = depTy->getAs()) { - subs[subTy->getCanonicalType().getPointer()] = replacement; - } - else if (auto dTy = depTy->getAs()) { - subs[dTy->getCanonicalType().getPointer()] = replacement; - } + auto sub = subs.front(); + subs = subs.slice(1); + + auto canTy = depTy->getCanonicalType().getPointer(); + subMap[canTy] = sub.getReplacement(); + conformanceMap[canTy] = sub.getConformances(); } - assert(args.empty() && "did not use all substitutions?!"); - return subs; + assert(subs.empty() && "did not use all substitutions?!"); } void GenericSignature:: getSubstitutions(ModuleDecl &mod, const TypeSubstitutionMap &subs, GenericSignature::LookupConformanceFn lookupConformance, - SmallVectorImpl &result) { + SmallVectorImpl &result) const { auto &ctx = getASTContext(); Type currentReplacement; SmallVector currentConformances; for (const auto &req : getRequirements()) { + auto depTy = req.getFirstType()->getCanonicalType(); + switch (req.getKind()) { case RequirementKind::Conformance: { // Get the conformance and record it. auto protoType = req.getSecondType()->castTo(); currentConformances.push_back( - lookupConformance(currentReplacement, protoType)); + lookupConformance(depTy, currentReplacement, protoType)); break; } @@ -473,6 +237,77 @@ getSubstitutions(ModuleDecl &mod, } } +static Optional +lookupDependentConformance(ProtocolDecl *proto, + ArrayRef conformances) { + for (ProtocolConformanceRef found : conformances) { + auto foundProto = found.getRequirement(); + if (foundProto == proto) { + return found; + } else if (foundProto->inheritsFrom(proto)) { + if (found.isConcrete()) { + return ProtocolConformanceRef( + found.getConcrete()->getInheritedConformance(proto)); + } + + return found; + } + } + + return None; +} + +static Optional +lookupDependentConformance(CanType original, + ProtocolDecl *proto, + const TypeConformanceMap &conformanceMap) { + // Check for conformances for the type that apply to the original type. + auto it = conformanceMap.find(original.getPointer()); + if (it != conformanceMap.end()) { + if (auto conformance = lookupDependentConformance(proto, it->second)) { + return conformance; + } + } + + // Check if we have substitutions for the parent. + if (auto memberTy = dyn_cast(original)) { + if (auto parent = memberTy->getBase()) { + auto *assocType = memberTy->getAssocType(); + auto *parentProto = assocType->getProtocol(); + auto conformance = lookupDependentConformance( + parent->getCanonicalType(), parentProto, conformanceMap); + + if (conformance) { + if (!conformance->isConcrete()) + return ProtocolConformanceRef(proto); + + auto sub = conformance->getConcrete()->getTypeWitnessSubstAndDecl( + assocType, nullptr).first; + + return lookupDependentConformance(proto, sub.getConformances()); + } + } + } + + return None; +} + +void GenericSignature:: +getSubstitutions(ModuleDecl &mod, + const TypeSubstitutionMap &subMap, + const TypeConformanceMap &conformanceMap, + SmallVectorImpl &result) const { + auto lookupConformanceFn = + [&](CanType original, Type replacement, ProtocolType *protoType) + -> ProtocolConformanceRef { + return *lookupDependentConformance(original, + protoType->getDecl(), + conformanceMap); + }; + + getSubstitutions(mod, subMap, lookupConformanceFn, result); +} + bool GenericSignature::requiresClass(Type type, ModuleDecl &mod) { if (!type->isTypeParameter()) return false; @@ -652,5 +487,7 @@ CanType GenericSignature::getCanonicalTypeInContext(Type type, ModuleDecl &mod) } }); - return type->getCanonicalType(); + auto result = type->getCanonicalType(); + assert(isCanonicalTypeInContext(result, mod)); + return result; } diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp index c7492e71cb6c4..2ace3ef13f2d6 100644 --- a/lib/AST/Mangle.cpp +++ b/lib/AST/Mangle.cpp @@ -361,10 +361,8 @@ void Mangler::bindGenericParameters(CanGenericSignature sig) { /// Bind the generic parameters from the given context and its parents. void Mangler::bindGenericParameters(const DeclContext *DC) { - if (auto sig = DC->getGenericSignatureOfContext()) { - Mod = DC->getParentModule(); - bindGenericParameters(sig->getCanonicalManglingSignature(*Mod)); - } + if (auto sig = DC->getGenericSignatureOfContext()) + bindGenericParameters(sig->getCanonicalSignature()); } static OperatorFixity getDeclFixity(const ValueDecl *decl) { @@ -496,8 +494,7 @@ Type Mangler::getDeclTypeForMangling(const ValueDecl *decl, initialParamDepth = 0; CanGenericSignature sig; if (auto gft = type->getAs()) { - assert(Mod); - sig = gft->getGenericSignature()->getCanonicalManglingSignature(*Mod); + sig = gft->getGenericSignature()->getCanonicalSignature(); CurGenericSignature = sig; genericParams = sig->getGenericParams(); requirements = sig->getRequirements(); @@ -682,8 +679,7 @@ void Mangler::mangleGenericSignatureParts( } void Mangler::mangleGenericSignature(const GenericSignature *sig) { - assert(Mod); - auto canSig = sig->getCanonicalManglingSignature(*Mod); + auto canSig = sig->getCanonicalSignature(); CurGenericSignature = canSig; mangleGenericSignatureParts(canSig->getGenericParams(), 0, canSig->getRequirements()); diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 14c9b9a9c1dea..a0598b8e88293 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -623,7 +623,7 @@ TypeBase::gatherAllSubstitutions(Module *module, } auto lookupConformanceFn = - [&](Type replacement, ProtocolType *protoType) + [&](CanType original, Type replacement, ProtocolType *protoType) -> ProtocolConformanceRef { auto *proto = protoType->getDecl(); @@ -668,8 +668,25 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol, ASTContext &ctx = getASTContext(); // An archetype conforms to a protocol if the protocol is listed in the - // archetype's list of conformances. + // archetype's list of conformances, or if the archetype has a superclass + // constraint and the superclass conforms to the protocol. if (auto archetype = type->getAs()) { + + // The archetype builder drops conformance requirements that are made + // redundant by a superclass requirement, so check for a cocnrete + // conformance first, since an abstract conformance might not be + // able to be resolved by a substitution that makes the archetype + // concrete. + if (auto super = archetype->getSuperclass()) { + if (auto inheritedConformance = lookupConformance(super, protocol, + resolver)) { + return ProtocolConformanceRef( + ctx.getInheritedConformance( + type, + inheritedConformance->getConcrete())); + } + } + if (protocol->isSpecificProtocol(KnownProtocolKind::AnyObject)) { if (archetype->requiresClass()) return ProtocolConformanceRef(protocol); @@ -682,8 +699,7 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol, return ProtocolConformanceRef(protocol); } - if (!archetype->getSuperclass()) - return None; + return None; } // An existential conforms to a protocol if the protocol is listed in the @@ -727,21 +743,6 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol, return None; } - // Check for protocol conformance of archetype via superclass requirement. - if (auto archetype = type->getAs()) { - if (auto super = archetype->getSuperclass()) { - if (auto inheritedConformance = lookupConformance(super, protocol, - resolver)) { - return ProtocolConformanceRef( - ctx.getInheritedConformance( - type, - inheritedConformance->getConcrete())); - } - - return None; - } - } - // UnresolvedType is a placeholder for an unknown type used when generating // diagnostics. We consider it to conform to all protocols, since the // intended type might have. @@ -750,8 +751,7 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol, ctx.getConformance(type, protocol, protocol->getLoc(), this, ProtocolConformanceState::Complete)); } - - + auto nominal = type->getAnyNominal(); // If we don't have a nominal type, there are no conformances. diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 37555cf13e118..f1526904e6628 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -448,7 +448,6 @@ bool ProtocolConformance::isVisibleFrom(const DeclContext *dc) const { ProtocolConformance *ProtocolConformance::subst(Module *module, Type substType, - ArrayRef subs, TypeSubstitutionMap &subMap, ArchetypeConformanceMap &conformanceMap) { if (getType()->isEqual(substType)) @@ -476,7 +475,7 @@ ProtocolConformance *ProtocolConformance::subst(Module *module, = cast(this)->getInheritedConformance(); ProtocolConformance *newBase; if (inheritedConformance->getType()->isSpecialized()) { - newBase = inheritedConformance->subst(module, substType, subs, subMap, + newBase = inheritedConformance->subst(module, substType, subMap, conformanceMap); } else { newBase = inheritedConformance; @@ -491,7 +490,7 @@ ProtocolConformance *ProtocolConformance::subst(Module *module, SmallVector newSubs; newSubs.reserve(spec->getGenericSubstitutions().size()); for (auto &sub : spec->getGenericSubstitutions()) - newSubs.push_back(sub.subst(module, subs, subMap, conformanceMap)); + newSubs.push_back(sub.subst(module, subMap, conformanceMap)); auto ctxNewSubs = module->getASTContext().AllocateCopy(newSubs); @@ -531,7 +530,7 @@ ProtocolConformance::getInheritedConformance(ProtocolDecl *protocol) const { env->getSubstitutionMap(conformingModule, sig, subs, subMap, conformanceMap); - auto r = inherited->subst(conformingModule, getType(), subs, + auto r = inherited->subst(conformingModule, getType(), subMap, conformanceMap); assert(getType()->isEqual(r->getType()) && "substitution didn't produce conformance for same type?!"); diff --git a/lib/AST/Substitution.cpp b/lib/AST/Substitution.cpp index 2e2b92b28a444..82b0c1f78dd65 100644 --- a/lib/AST/Substitution.cpp +++ b/lib/AST/Substitution.cpp @@ -50,11 +50,64 @@ Substitution Substitution::subst(Module *module, assert(sig && env); env->getSubstitutionMap(module, sig, subs, subMap, conformanceMap); - return subst(module, subs, subMap, conformanceMap); + return subst(module, subMap, conformanceMap); +} + +static Optional +lookupArchetypeConformance(ProtocolDecl *proto, + ArrayRef conformances) { + for (ProtocolConformanceRef found : conformances) { + auto foundProto = found.getRequirement(); + if (foundProto == proto) { + return found; + } else if (foundProto->inheritsFrom(proto)) { + if (found.isConcrete()) { + return ProtocolConformanceRef( + found.getConcrete()->getInheritedConformance(proto)); + } + + return found; + } + } + + return None; +} + +static Optional +lookupArchetypeConformance(ArchetypeType *replacement, + ProtocolDecl *proto, + ArchetypeConformanceMap &conformanceMap) { + // Check for conformances for the type that apply to the original + // substituted archetype. + auto it = conformanceMap.find(replacement); + if (it != conformanceMap.end()) { + if (auto conformance = lookupArchetypeConformance(proto, it->second)) { + return conformance; + } + } + + // Check if we have substitutions for the parent. + if (auto *parent = replacement->getParent()) { + auto *assocType = replacement->getAssocType(); + auto *parentProto = assocType->getProtocol(); + auto conformance = + lookupArchetypeConformance(parent, parentProto, conformanceMap); + + if (conformance) { + if (!conformance->isConcrete()) + return ProtocolConformanceRef(proto); + + auto sub = conformance->getConcrete()->getTypeWitnessSubstAndDecl( + assocType, nullptr).first; + + return lookupArchetypeConformance(proto, sub.getConformances()); + } + } + + return None; } Substitution Substitution::subst(Module *module, - ArrayRef subs, TypeSubstitutionMap &subMap, ArchetypeConformanceMap &conformanceMap) const { // Substitute the replacement. @@ -76,7 +129,7 @@ Substitution Substitution::subst(Module *module, // If we have a concrete conformance, we need to substitute the // conformance to apply to the new type. if (c.isConcrete()) { - auto substC = c.getConcrete()->subst(module, substReplacement, subs, + auto substC = c.getConcrete()->subst(module, substReplacement, subMap, conformanceMap); substConformances.push_back(ProtocolConformanceRef(substC)); if (c != substConformances.back()) @@ -90,25 +143,8 @@ Substitution Substitution::subst(Module *module, // If the original type was an archetype, check the conformance map. if (auto replacementArch = Replacement->getAs()) { - // Check for conformances for the type that apply to the original - // substituted archetype. - auto it = conformanceMap.find(replacementArch); - assert(it != conformanceMap.end()); - for (ProtocolConformanceRef found : it->second) { - auto foundProto = found.getRequirement(); - if (foundProto == proto) { - conformance = found; - break; - } else if (foundProto->inheritsFrom(proto)) { - if (found.isConcrete()) { - conformance = ProtocolConformanceRef( - found.getConcrete()->getInheritedConformance(proto)); - } else { - conformance = found; - } - break; - } - } + conformance = lookupArchetypeConformance(replacementArch, proto, + conformanceMap); } // If that didn't find anything, we can still synthesize AnyObject diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 9706fab221802..c1427376fa339 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2961,6 +2961,23 @@ Type Type::subst(Module *module, }); } +Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass, + LazyResolver *resolver) { + Type derivedType = this; + + while (derivedType) { + auto *derivedClass = derivedType->getClassOrBoundGenericClass(); + assert(derivedClass && "expected a class here"); + + if (derivedClass == baseClass) + return derivedType; + + derivedType = derivedType->getSuperclass(resolver); + } + + llvm_unreachable("no inheritance relationship between given classes"); +} + TypeSubstitutionMap TypeBase::getMemberSubstitutions(const DeclContext *dc) { // Ignore lvalues in the base type. @@ -2990,12 +3007,14 @@ TypeSubstitutionMap TypeBase::getMemberSubstitutions(const DeclContext *dc) { LazyResolver *resolver = dc->getASTContext().getLazyResolver(); // Find the superclass type with the context matching that of the member. - auto ownerNominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); - while (!baseTy->is() && - baseTy->getAnyNominal() && - baseTy->getAnyNominal() != ownerNominal) { - baseTy = baseTy->getSuperclass(resolver); - assert(baseTy && "Couldn't find appropriate context"); + // + // FIXME: Do this in the caller? + if (baseTy->getAnyNominal()) { + auto *ownerNominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); + if (auto *ownerClass = dyn_cast(ownerNominal)) + baseTy = baseTy->getSuperclassForDecl(ownerClass, resolver); + + assert(ownerNominal == baseTy->getAnyNominal()); } // If the base type isn't specialized, there's nothing to substitute. @@ -3442,23 +3461,27 @@ case TypeKind::Id: if (!firstType) return Type(); + if (firstType.getPointer() != req.getFirstType().getPointer()) + anyChanges = true; + Type secondType = req.getSecondType(); if (secondType) { secondType = secondType.transform(fn); if (!secondType) return Type(); - } - if (firstType->hasTypeParameter() || - (secondType && secondType->hasTypeParameter())) { - if (firstType.getPointer() != req.getFirstType().getPointer() || - secondType.getPointer() != req.getSecondType().getPointer()) + if (secondType.getPointer() != req.getSecondType().getPointer()) anyChanges = true; + } - requirements.push_back(Requirement(req.getKind(), firstType, - secondType)); - } else - anyChanges = true; + if (!firstType->isTypeParameter()) { + if (!secondType || !secondType->isTypeParameter()) + continue; + std::swap(firstType, secondType); + } + + requirements.push_back(Requirement(req.getKind(), firstType, + secondType)); } // Transform input type. diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 1c93bf600b709..e90764b72be3d 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -195,13 +195,8 @@ void PolymorphicConvention::addPseudogenericFulfillments() { void PolymorphicConvention::enumerateRequirements(const RequirementCallback &callback) { if (!Generics) return; - // Note that the canonical mangling signature will sometimes use - // different dependent type from Generics, apparently for no good - // reason. - auto minimized = Generics->getCanonicalManglingSignature(M); - // Make a first pass to get all the type metadata. - for (auto &reqt : minimized->getRequirements()) { + for (auto &reqt : Generics->getRequirements()) { switch (reqt.getKind()) { // Ignore these; they don't introduce extra requirements. case RequirementKind::Superclass: @@ -220,7 +215,7 @@ void PolymorphicConvention::enumerateRequirements(const RequirementCallback &cal } // Make a second pass for all the protocol conformances. - for (auto &reqt : minimized->getRequirements()) { + for (auto &reqt : Generics->getRequirements()) { switch (reqt.getKind()) { // Ignore these; they don't introduce extra requirements. case RequirementKind::Superclass: @@ -258,9 +253,6 @@ void PolymorphicConvention::enumerateUnfulfilledRequirements(const RequirementCa } void PolymorphicConvention::initGenerics() { - // The canonical mangling signature removes dependent types that are - // equal to concrete types, but isn't necessarily parallel with - // substitutions. Generics = FnType->getGenericSignature(); } @@ -669,10 +661,23 @@ static unsigned getDependentTypeIndex(CanGenericSignature generics, static unsigned getProtocolConformanceIndex(CanGenericSignature generics, ModuleDecl &M, CanType type, ProtocolDecl *protocol) { - auto conformsTo = generics->getConformsTo(type, M); - auto it = std::find(conformsTo.begin(), conformsTo.end(), protocol); - assert(it != conformsTo.end() && "didn't find protocol in conformances"); - return (it - conformsTo.begin()); + assert(type->isTypeParameter()); + + // Make a pass over all the dependent types. + unsigned index = 0; + for (auto reqt : generics->getRequirements()) { + // Unfortunately, we can't rely on either depTy or type actually + // being the marked witness type in the generic signature, so we have + // to ask the generic signature whether the types are equal. + if (reqt.getKind() == RequirementKind::Conformance && + generics->areSameTypeParameterInContext(reqt.getFirstType(), type, M)) { + if (reqt.getSecondType()->getAnyNominal() == protocol) + return index; + index++; + } + } + + llvm_unreachable("didn't find dependent type in all-dependent-types list"); } namespace { diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp index c8dc4a633fad6..65918f626a4c3 100644 --- a/lib/Parse/ParseSIL.cpp +++ b/lib/Parse/ParseSIL.cpp @@ -1466,9 +1466,11 @@ static bool allowAbstractConformance(Parser &P, Type subReplacement, /// Collect conformances by looking up the conformance from replacement /// type and protocol decl in GenericParamList. static bool getConformancesForSubstitution(Parser &P, - ArchetypeType *subArchetype, Type subReplacement, SourceLoc loc, + ArrayRef protocols, + Type subReplacement, + SourceLoc loc, SmallVectorImpl &conformances) { - for (auto proto : subArchetype->getConformsTo()) { + for (auto proto : protocols) { // Try looking up a concrete conformance. if (auto conformance = getConformanceOfReplacement(P, subReplacement, proto)) { @@ -1508,17 +1510,20 @@ bool getApplySubstitutionsFromParsed( auto loc = params->getRAngleLoc(); - // Map from interface types to archetypes - TypeSubstitutionMap map = env->getInterfaceToArchetypeMap(); - - auto *mod = SP.SILMod.getSwiftModule(); + // Collect conformance requirements in a convenient form. + llvm::DenseMap> conformsTo; + for (auto reqt : sig->getRequirements()) { + if (reqt.getKind() == RequirementKind::Conformance) { + auto canTy = reqt.getFirstType()->getCanonicalType(); + auto nominal = reqt.getSecondType()->getAnyNominal(); + conformsTo[canTy.getPointer()].push_back(cast(nominal)); + } + } - // The replacement is for the corresponding archetype by ordering. + // The replacement is for the corresponding dependent type by ordering. for (auto depTy : sig->getAllDependentTypes()) { - // Map the interface type to a context type. - auto contextTy = depTy.subst(mod, map, SubstOptions()); - auto *archetype = contextTy->castTo(); + auto canTy = depTy->getCanonicalType().getPointer(); if (parses.empty()) { SP.P.diagnose(loc, diag::sil_missing_substitutions); @@ -1528,7 +1533,7 @@ bool getApplySubstitutionsFromParsed( parses = parses.slice(1); SmallVector conformances; - if (getConformancesForSubstitution(SP.P, archetype, + if (getConformancesForSubstitution(SP.P, conformsTo[canTy], parsed.replacement, parsed.loc, conformances)) return true; diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp index dc73acbd1b275..5037fc021c52e 100644 --- a/lib/SIL/SILModule.cpp +++ b/lib/SIL/SILModule.cpp @@ -12,6 +12,8 @@ #define DEBUG_TYPE "sil-module" #include "swift/Serialization/SerializedSILLoader.h" +#include "swift/AST/GenericEnvironment.h" +#include "swift/AST/Substitution.h" #include "swift/SIL/FormalLinkage.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILModule.h" @@ -641,52 +643,10 @@ SerializedSILLoader *SILModule::getSILLoader() { return SILLoader.get(); } -static ArrayRef -getSubstitutionsForProtocolConformance(ProtocolConformanceRef CRef) { - if (CRef.isAbstract()) - return {}; - - auto C = CRef.getConcrete(); - - // Walk down to the base NormalProtocolConformance. - ArrayRef Subs; - const ProtocolConformance *ParentC = C; - while (!isa(ParentC)) { - switch (ParentC->getKind()) { - case ProtocolConformanceKind::Normal: - llvm_unreachable("should have exited the loop?!"); - case ProtocolConformanceKind::Inherited: - ParentC = cast(ParentC) - ->getInheritedConformance(); - break; - case ProtocolConformanceKind::Specialized: { - auto SC = cast(ParentC); - ParentC = SC->getGenericConformance(); - assert(Subs.empty() && "multiple conformance specializations?!"); - Subs = SC->getGenericSubstitutions(); - break; - } - } - } - const NormalProtocolConformance *NormalC - = cast(ParentC); - - // If the normal conformance is for a generic type, and we didn't hit a - // specialized conformance, collect the substitutions from the generic type. - // FIXME: The AST should do this for us. - if (NormalC->getType()->isSpecialized() && Subs.empty()) { - Subs = NormalC->getType() - ->gatherAllSubstitutions(NormalC->getDeclContext()->getParentModule(), - nullptr); - } - - return Subs; -} - /// \brief Given a conformance \p C and a protocol requirement \p Requirement, /// search the witness table for the conformance and return the witness thunk -/// for the requirement, together with any substitutions for the conformance. -std::tuple> +/// for the requirement. +std::pair SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C, SILDeclRef Requirement) { // Look up the witness table associated with our protocol conformance from the @@ -697,7 +657,7 @@ SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C, if (!Ret) { DEBUG(llvm::dbgs() << " Failed speculative lookup of witness for: "; C.dump(); Requirement.dump()); - return std::make_tuple(nullptr, nullptr, ArrayRef()); + return std::make_pair(nullptr, nullptr); } // Okay, we found the correct witness table. Now look for the method. @@ -711,11 +671,10 @@ SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C, if (MethodEntry.Requirement != Requirement) continue; - return std::make_tuple(MethodEntry.Witness, Ret, - getSubstitutionsForProtocolConformance(C)); + return std::make_pair(MethodEntry.Witness, Ret); } - return std::make_tuple(nullptr, nullptr, ArrayRef()); + return std::make_pair(nullptr, nullptr); } /// \brief Given a protocol \p Protocol and a requirement \p Requirement, diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index ba393c71ba239..dc4ec7fc69f33 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -424,12 +424,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// Mark protocol conformances from the given set of substitutions as used. void useConformancesFromSubstitutions(ArrayRef subs); - /// Substitute the `Self` type from a protocol conformance into a protocol - /// requirement's type to get the type of the witness. - CanAnyFunctionType - substSelfTypeIntoProtocolRequirementType(CanGenericFunctionType reqtTy, - ProtocolConformance *conformance); - /// Emit a `mark_function_escape` instruction for top-level code when a /// function or closure at top level refers to script globals. void emitMarkFunctionEscapeForTopLevelCodeGlobals(SILLocation loc, diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index 362846c05b7e4..3df6692ff6c10 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -1675,6 +1675,178 @@ static bool maybeOpenCodeProtocolWitness(SILGenFunction &gen, return false; } +static void addConformanceToSubstitutionMap(SILModule &M, + TypeSubstitutionMap &subs, + GenericEnvironment *genericEnv, + CanType base, + const ProtocolConformance *conformance) { + conformance->forEachTypeWitness(nullptr, [&](AssociatedTypeDecl *assocTy, + Substitution sub, + TypeDecl *) -> bool { + auto depTy = + CanDependentMemberType::get(base, assocTy, M.getASTContext()); + auto replacement = sub.getReplacement()->getCanonicalType(); + replacement = ArchetypeBuilder::mapTypeOutOfContext(M.getSwiftModule(), + genericEnv, + replacement) + ->getCanonicalType(); + subs.insert({depTy.getPointer(), replacement}); + for (auto conformance : sub.getConformances()) { + if (conformance.isAbstract()) + continue; + addConformanceToSubstitutionMap(M, subs, genericEnv, + depTy, conformance.getConcrete()); + } + return false; + }); +} + +/// Substitute the `Self` type from a protocol conformance into a protocol +/// requirement's type to get the type of the witness. +static CanAnyFunctionType +substSelfTypeIntoProtocolRequirementType(SILModule &M, + CanGenericFunctionType reqtTy, + ProtocolConformance *conformance) { + if (conformance == nullptr) { + // Default witness thunks just get the requirement type without + // substituting Self. + return reqtTy; + } + + // Build a substitution map to replace `self` and its associated types. + auto &C = M.getASTContext(); + CanType selfParamTy = CanGenericTypeParamType::get(0, 0, C); + + TypeSubstitutionMap subs; + subs.insert({selfParamTy.getPointer(), conformance->getInterfaceType() + ->getCanonicalType()}); + addConformanceToSubstitutionMap(M, subs, + conformance->getGenericEnvironment(), + selfParamTy, conformance); + + ArchetypeBuilder builder(*M.getSwiftModule(), + M.getASTContext().Diags); + + SmallVector allParams; + + // Add the outer generic signature of the witness. + if (auto *outerSig = conformance->getGenericSignature()) { + allParams.append(outerSig->getGenericParams().begin(), + outerSig->getGenericParams().end()); + builder.addGenericSignature(outerSig, nullptr); + } + + // Now we look at the generic signature of the requirement. + // We are going to drop `Self`, and requirements rooted in `Self`. + for (auto *param : reqtTy->getGenericParams().slice(1)) { + allParams.push_back(param); + builder.addGenericParameter(param); + } + + auto rootedInSelf = [&](Type t) -> bool { + while (auto dmt = t->getAs()) { + t = dmt->getBase(); + } + return t->isEqual(selfParamTy); + }; + + RequirementSource source(RequirementSource::Explicit, SourceLoc()); + + for (auto &reqt : reqtTy->getRequirements()) { + if (rootedInSelf(reqt.getFirstType())) + continue; + + switch (reqt.getKind()) { + case RequirementKind::Conformance: + case RequirementKind::Superclass: + case RequirementKind::WitnessMarker: + builder.addRequirement(reqt, source); + break; + + case RequirementKind::SameType: { + if (rootedInSelf(reqt.getSecondType())) + continue; + + // Substitute the constrained types. + auto first = reqt.getFirstType().subst(M.getSwiftModule(), subs, + SubstFlags::IgnoreMissing); + auto second = reqt.getSecondType().subst(M.getSwiftModule(), subs, + SubstFlags::IgnoreMissing); + + if (!first->isTypeParameter()) { + assert(second->isTypeParameter()); + std::swap(first, second); + } + + builder.addRequirement(Requirement(RequirementKind::SameType, + first, second), source); + break; + } + } + } + + // Substitute away `Self` in parameter and result types. + auto input = reqtTy->getInput().subst(M.getSwiftModule(), subs, + SubstFlags::IgnoreMissing) + ->getCanonicalType(); + auto result = reqtTy->getResult().subst(M.getSwiftModule(), subs, + SubstFlags::IgnoreMissing) + ->getCanonicalType(); + + // The result might be fully concrete, if the witness had no generic + // signature, and the requirement had no additional generic parameters + // beyond `Self`. + if (!allParams.empty()) { + auto invalid = builder.finalize(SourceLoc()); + assert(!invalid && "invalid requirements should not be seen in SIL"); + + auto *sig = builder.getGenericSignature(allParams); + + return cast( + GenericFunctionType::get(sig, input, result, reqtTy->getExtInfo()) + ->getCanonicalType()); + } + + return CanFunctionType::get(input, result, reqtTy->getExtInfo()); +} + +static GenericEnvironment * +getSubstitutedGenericEnvironment(SILModule &M, + GenericEnvironment *reqtEnv, + CanGenericSignature witnessSig, + ProtocolConformance *conformance) { + if (conformance == nullptr) { + // Default witness thunks just use the context archetypes of the requirement. + return reqtEnv; + } + + TypeSubstitutionMap witnessContextParams; + + // Outer generic parameters come from the generic context of + // the conformance (which might not be the same as the generic + // context of the witness, if the witness is defined in a + // superclass, concrete extension or protocol extension). + if (auto *outerEnv = conformance->getGenericEnvironment()) + witnessContextParams = outerEnv->getInterfaceToArchetypeMap(); + + // Inner generic parameters come from the requirement and + // also map to the archetypes of the requirement. + for (auto pair : reqtEnv->getInterfaceToArchetypeMap()) { + // Skip the 'Self' parameter and friends. + if (auto *archetypeTy = pair.second->getAs()) + if (archetypeTy->isSelfDerived()) + continue; + + auto result = witnessContextParams.insert(pair); + assert(result.second); + } + + if (!witnessContextParams.empty()) + return GenericEnvironment::get(M.getASTContext(), witnessContextParams); + + return nullptr; +} + SILFunction * SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, SILLinkage linkage, @@ -1683,6 +1855,7 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, IsFreeFunctionWitness_t isFree, ArrayRef witnessSubs) { auto requirementInfo = Types.getConstantInfo(requirement); + auto witnessInfo = Types.getConstantInfo(witness); unsigned witnessUncurryLevel = witness.uncurryLevel; // If the witness is a free function, consider the self argument @@ -1699,43 +1872,10 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, // Work out the lowered function type of the SIL witness thunk. auto reqtOrigTy = cast(requirementInfo.LoweredInterfaceType); - CanAnyFunctionType reqtSubstTy; - - if (conformance) { - // Substitute the 'Self' type into the requirement to get the concrete witness - // type, leaving the other generic parameters open. - reqtSubstTy = - substSelfTypeIntoProtocolRequirementType(reqtOrigTy, conformance); - - // If the conformance is generic, its generic parameters apply to the witness. - GenericSignature *sig = conformance->getGenericSignature(); - if (sig) { - if (auto gft = dyn_cast(reqtSubstTy)) { - SmallVector allParams(sig->getGenericParams().begin(), - sig->getGenericParams().end()); - allParams.append(gft->getGenericParams().begin(), - gft->getGenericParams().end()); - SmallVector allReqts(sig->getRequirements().begin(), - sig->getRequirements().end()); - allReqts.append(gft->getRequirements().begin(), - gft->getRequirements().end()); - sig = GenericSignature::get(allParams, allReqts); - } + auto reqtSubstTy + = substSelfTypeIntoProtocolRequirementType(M, reqtOrigTy, conformance); - reqtSubstTy = cast( - GenericFunctionType::get(sig, - reqtSubstTy.getInput(), - reqtSubstTy.getResult(), - reqtSubstTy->getExtInfo()) - ->getCanonicalType()); - } - } else { - // Default witness thunks just get the requirement type without - // substituting Self. - reqtSubstTy = reqtOrigTy; - } - - // Lower the witness type with the requirement's abstraction level. + // Lower the witness thunk type with the requirement's abstraction level. auto witnessSILFnType = getNativeSILFunctionType(M, AbstractionPattern(reqtOrigTy), reqtSubstTy); @@ -1769,35 +1909,15 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, nameBuffer = mangler.finalize(); } - // Collect the generic environment for the witness. - TypeSubstitutionMap witnessContextParams; - - // Concrete witness thunks use the context archetypes of the conformance. - if (conformance) { - if (auto *genericEnv = conformance->getGenericEnvironment()) - witnessContextParams = genericEnv->getInterfaceToArchetypeMap(); - - // If the requirement is generic, reparent the requirement parameters to - // the conformance parameters. - for (auto pair : requirementInfo.GenericEnv->getInterfaceToArchetypeMap()) { - // Skip the 'Self' parameter. - if (auto *archetypeTy = pair.second->getAs()) - if (archetypeTy->getSelfProtocol() != nullptr) - continue; - - auto result = witnessContextParams.insert(pair); - assert(result.second); - } - - // Default witness thunks use the context archetypes of the requirement. - } else { - witnessContextParams = requirementInfo.GenericEnv - ->getInterfaceToArchetypeMap(); - } + CanGenericSignature witnessSig; + if (auto gft = dyn_cast( + witnessInfo.LoweredInterfaceType)) + witnessSig = gft.getGenericSignature(); - GenericEnvironment *witnessEnv = nullptr; - if (!witnessContextParams.empty()) - witnessEnv = GenericEnvironment::get(getASTContext(), witnessContextParams); + // Collect the generic environment for the witness. + GenericEnvironment *requirementEnv = requirementInfo.GenericEnv; + GenericEnvironment *witnessEnv = getSubstitutedGenericEnvironment( + M, requirementEnv, witnessSig, conformance); // If the thunked-to function is set to be always inlined, do the // same with the witness, on the theory that the user wants all diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 8f47b27f8bb85..dd5a4d4bbeee1 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -2822,119 +2822,6 @@ static CanType dropLastElement(CanType type) { return TupleType::get(elts, type->getASTContext())->getCanonicalType(); } -static void addConformanceToSubstitutionMap(SILGenModule &SGM, - TypeSubstitutionMap &subs, - GenericEnvironment *genericEnv, - CanType base, - const ProtocolConformance *conformance) { - conformance->forEachTypeWitness(nullptr, [&](AssociatedTypeDecl *assocTy, - Substitution sub, - TypeDecl *) -> bool { - auto depTy = - CanDependentMemberType::get(base, assocTy, SGM.getASTContext()); - auto replacement = sub.getReplacement()->getCanonicalType(); - replacement = ArchetypeBuilder::mapTypeOutOfContext(SGM.M.getSwiftModule(), - genericEnv, - replacement) - ->getCanonicalType(); - subs.insert({depTy.getPointer(), replacement}); - for (auto conformance : sub.getConformances()) { - if (conformance.isAbstract()) - continue; - addConformanceToSubstitutionMap(SGM, subs, genericEnv, - depTy, conformance.getConcrete()); - } - return false; - }); -} - -/// Substitute the `Self` type from a protocol conformance into a protocol -/// requirement's type to get the type of the witness. -CanAnyFunctionType SILGenModule:: -substSelfTypeIntoProtocolRequirementType(CanGenericFunctionType reqtTy, - ProtocolConformance *conformance) { - // Build a substitution map to replace `self` and its associated types. - auto &C = M.getASTContext(); - CanType selfParamTy = CanGenericTypeParamType::get(0, 0, C); - - TypeSubstitutionMap subs; - subs.insert({selfParamTy.getPointer(), conformance->getInterfaceType() - ->getCanonicalType()}); - addConformanceToSubstitutionMap(*this, subs, - conformance->getGenericEnvironment(), - selfParamTy, conformance); - - // Drop requirements rooted in the applied generic parameters. - SmallVector unappliedReqts; - auto rootedInSelf = [&](Type t) -> bool { - while (auto dmt = t->getAs()) { - t = dmt->getBase(); - } - return t->isEqual(selfParamTy); - }; - - #if 0 - llvm::errs() << "--\n"; - for (auto &pair : subs) { - pair.first->print(llvm::errs()); - llvm::errs() << " => "; - pair.second->dump(); - llvm::errs() << "\n"; - } - #endif - - // Get the unapplied params. - auto unappliedParams = reqtTy->getGenericParams().slice(1); - - // Get the requirements that aren't rooted in the applied 'self' parameter. - for (auto &reqt : reqtTy->getRequirements()) { - switch (reqt.getKind()) { - case RequirementKind::Conformance: - case RequirementKind::Superclass: - case RequirementKind::WitnessMarker: - // Substituting the parameter eliminates conformance constraints rooted - // in the parameter. - if (rootedInSelf(reqt.getFirstType())) - continue; - break; - - case RequirementKind::SameType: { - // Same-type constraints are eliminated if both sides of the constraint - // are rooted in substituted parameters. - if (rootedInSelf(reqt.getFirstType()) - && rootedInSelf(reqt.getSecondType())) - continue; - - // Otherwise, substitute the constrained types. - unappliedReqts.push_back( - Requirement(RequirementKind::SameType, - reqt.getFirstType().subst(M.getSwiftModule(), subs, - SubstFlags::IgnoreMissing), - reqt.getSecondType().subst(M.getSwiftModule(), subs, - SubstFlags::IgnoreMissing))); - continue; - } - } - unappliedReqts.push_back(reqt); - } - - auto input = reqtTy->getInput().subst(M.getSwiftModule(), subs, - SubstFlags::IgnoreMissing) - ->getCanonicalType(); - auto result = reqtTy->getResult().subst(M.getSwiftModule(), subs, - SubstFlags::IgnoreMissing) - ->getCanonicalType(); - - if (!unappliedParams.empty() && !unappliedReqts.empty()) { - auto sig = GenericSignature::get(unappliedParams, - unappliedReqts)->getCanonicalSignature(); - - return CanGenericFunctionType::get(sig, input, result, reqtTy->getExtInfo()); - } else { - return CanFunctionType::get(input, result, reqtTy->getExtInfo()); - } -} - void SILGenFunction::emitProtocolWitness(Type selfType, AbstractionPattern reqtOrigTy, CanAnyFunctionType reqtSubstTy, diff --git a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp index 8a3ababd1e7f4..8de6aadddda8f 100644 --- a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp @@ -137,11 +137,10 @@ void CalleeCache::computeMethodCallees() { SILFunction * CalleeCache::getSingleCalleeForWitnessMethod(WitnessMethodInst *WMI) const { SILFunction *CalleeFn; - ArrayRef Subs; SILWitnessTable *WT; // Attempt to find a specific callee for the given conformance and member. - std::tie(CalleeFn, WT, Subs) = WMI->getModule().lookUpFunctionInWitnessTable( + std::tie(CalleeFn, WT) = WMI->getModule().lookUpFunctionInWitnessTable( WMI->getConformance(), WMI->getMember()); return CalleeFn; diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp index 60a0fc1680ffb..4460b27161326 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp @@ -1277,10 +1277,9 @@ SILInstruction *SILCombiner::visitWitnessMethodInst(WitnessMethodInst *WMI) { // Many cases are handled by the inliner/devirtualizer, but certain // special cases are not covered there, e.g. partial_apply(witness_method) SILFunction *F; - ArrayRef Subs; SILWitnessTable *WT; - std::tie(F, WT, Subs) = + std::tie(F, WT) = WMI->getModule().lookUpFunctionInWitnessTable(WMI->getConformance(), WMI->getMember()); diff --git a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp index 0fe0ad3ffe068..0530fa330cd2c 100644 --- a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp +++ b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp @@ -330,7 +330,7 @@ static bool tryToSpeculateTarget(FullApplySite AI, // Bail if any generic types parameters of the class instance type are // unbound. // We cannot devirtualize unbound generic calls yet. - if (isNominalTypeWithUnboundGenericParameters(SubType, AI.getModule())) + if (SubType.getSwiftRValueType()->hasArchetype()) return false; auto &M = CMI->getModule(); diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index aa09a9c46d017..464256c164897 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -268,179 +268,75 @@ static SILValue getInstanceWithExactDynamicType(SILValue S, SILModule &M, return SILValue(); } -/// Return bound generic type for the unbound type Superclass, -/// which is a superclass of a bound generic type BoundDerived -/// (Base may be also the same as BoundDerived or may be -/// non-generic at all). -static CanType bindSuperclass(CanType Superclass, - SILType BoundDerived) { - assert(BoundDerived && "Expected non-null type!"); - - SILType BoundSuperclass = BoundDerived; - - do { - // Get declaration of the superclass. - auto *Decl = BoundSuperclass.getNominalOrBoundGenericNominal(); - // Obtain the unbound variant of the current superclass - CanType UnboundSuperclass = Decl->getDeclaredType()->getCanonicalType(); - // Check if we found a superclass we are looking for. - if (UnboundSuperclass == Superclass) - return BoundSuperclass.getSwiftRValueType(); - - // Get the superclass of current one - BoundSuperclass = BoundSuperclass.getSuperclass(nullptr); - } while (BoundSuperclass); - - llvm_unreachable("Expected to find a bound generic superclass!"); -} - -// Returns true if any generic types parameters of the class are -// unbound. -bool swift::isNominalTypeWithUnboundGenericParameters(SILType Ty, SILModule &M) { - auto *ND = Ty.getNominalOrBoundGenericNominal(); - if (ND && ND->getGenericSignature()) { - auto InstanceTypeSubsts = - Ty.gatherAllSubstitutions(M); - - if (!InstanceTypeSubsts.empty()) { - if (hasUnboundGenericTypes(InstanceTypeSubsts)) - return true; - } - } - - if (Ty.hasArchetype()) - return true; - - return false; -} // Start with the substitutions from the apply. // Try to propagate them to find out the real substitutions required // to invoke the method. -static ArrayRef -getSubstitutionsForCallee(SILModule &M, CanSILFunctionType GenCalleeType, - SILType ClassInstanceType, FullApplySite AI) { - // *NOTE*: - // Apply instruction substitutions are for the Member from a protocol or - // class B, where this member was first defined, before it got overridden by - // derived classes. - // - // The implementation F (the implementing method) which was found may have - // a different set of generic parameters, e.g. because it is implemented by a - // class D1 derived from B. - // - // ClassInstanceType may have a type different from both the type B - // the Member belongs to and from the ClassInstanceType, e.g. if - // ClassInstance is of a class D2, which is derived from D1, but does not - // override the Member. - // - // As a result, substitutions provided by AI are for Member, whereas - // substitutions in ClassInstanceType are for D2. And substitutions for D1 - // are not available directly in a general case. Therefore, they have to - // be computed. - // - // What we know for sure: - // B is a superclass of D1 - // D1 is a superclass of D2. - // D1 can be the same as D2. D1 can be the same as B. - // - // So, substitutions from AI are for class B. - // Substitutions for class D1 by means of bindSuperclass(), which starts - // with a bound type ClassInstanceType and checks its superclasses until it - // finds a bound superclass matching D1 and returns its substitutions. +static void +getSubstitutionsForCallee(SILModule &M, + CanSILFunctionType baseCalleeType, + CanType derivedSelfType, + FullApplySite AI, + SmallVectorImpl &newSubs) { + + // If the base method is not polymorphic, no substitutions are required, + // even if we originally had substitutions for calling the derived method. + if (!baseCalleeType->isPolymorphic()) + return; - // Class F belongs to. - CanType FSelfClass = GenCalleeType->getSelfParameter().getType(); + auto derivedClass = derivedSelfType; + if (auto metatypeType = dyn_cast(derivedClass)) + derivedClass = CanType(metatypeType->getInstanceType()); auto *Module = M.getSwiftModule(); - ArrayRef ClassSubs; - - if (GenCalleeType->isPolymorphic()) { - // Declaration of the class F belongs to. - if (auto *FSelfTypeDecl = FSelfClass.getNominalOrBoundGenericNominal()) { - // Get the unbound generic type F belongs to. - CanType FSelfGenericType = - FSelfTypeDecl->getDeclaredType()->getCanonicalType(); - - assert((isa(ClassInstanceType.getSwiftRValueType()) || - isa(ClassInstanceType.getSwiftRValueType())) && - "Self type should be either a bound generic type" - "or a non-generic type"); - - assert((isa(FSelfGenericType) || - isa(FSelfGenericType)) && - "Method implementation self type should be generic"); - - if (isa(ClassInstanceType.getSwiftRValueType())) { - auto BoundBaseType = bindSuperclass(FSelfGenericType, - ClassInstanceType); - ClassSubs = BoundBaseType->gatherAllSubstitutions(Module, nullptr); - } - } - } else { - // If the callee is not polymorphic, no substitutions are required. - return {}; - } - - if (ClassSubs.empty()) - return AI.getSubstitutions(); - - auto AISubs = AI.getSubstitutions(); - - CanSILFunctionType AIGenCalleeType = - AI.getCallee()->getType().castTo(); - - unsigned NextMethodParamIdx = 0; - unsigned NumMethodParams = 0; - if (AIGenCalleeType->isPolymorphic()) { - NextMethodParamIdx = AISubs.size(); - if (auto AIMethodSig = AI.getOrigCalleeType()->getGenericSignature()) { - // Find out if the apply instruction contains any substitutions for - // a method itself, not for the class where it is declared. - // If there are any such parameters, remember where they start - // in the substitutions list. - auto InnermostGenericParams = AIMethodSig->getInnermostGenericParams(); - auto InnermostGenericParamsNum = InnermostGenericParams.size(); - if (InnermostGenericParamsNum != AIMethodSig->getGenericParams().size()) { - auto Depth = InnermostGenericParams[0]->getDepth(); - for (NextMethodParamIdx = 0; NextMethodParamIdx < AISubs.size(); - ++NextMethodParamIdx) { - if (auto SubstTy = dyn_cast( - AISubs[NextMethodParamIdx].getReplacement().getPointer())) { - if (auto *GenParamTy = dyn_cast( - SubstTy->getOriginal().getPointer())) - if (GenParamTy->getDepth() == Depth) - break; - } - } - } - } - NumMethodParams = AISubs.size() - NextMethodParamIdx; - } - - unsigned NumSubs = ClassSubs.size() + NumMethodParams; + TypeSubstitutionMap subMap; + TypeConformanceMap conformanceMap; - if (ClassSubs.size() == NumSubs) - return ClassSubs; + if (auto derivedCalleeSig = AI.getOrigCalleeType()->getGenericSignature()) { + auto *derivedClassDecl = derivedClass->getClassOrBoundGenericClass(); + assert(derivedClassDecl && "self is not a class type"); - // Mix class subs with method specific subs from the AI substitutions. + auto derivedSubs = AI.getSubstitutions(); - // Assumptions: AI substitutions contain first the substitutions for - // a class of the method being invoked and then the substitutions - // for a method being invoked. - auto Subs = M.getASTContext().Allocate(NumSubs); + // Decompose the original substitution using the derived method signature. + derivedCalleeSig->getSubstitutionMap(derivedSubs, subMap, conformanceMap); - unsigned i = 0; - for (auto &S : ClassSubs) { - Subs[i++] = S; + // Drop any generic parameters that come from the derived class, leaving + // only generic parameters of the method itself. + if (auto derivedClassSig = derivedClassDecl->getGenericSignatureOfContext()) { + for (auto depTy : derivedClassSig->getAllDependentTypes()) { + auto canTy = depTy->getCanonicalType().getPointer(); + subMap.erase(canTy); + conformanceMap.erase(canTy); + } + } } - for (; i < NumSubs; ++i, ++NextMethodParamIdx) { - Subs[i] = AISubs[NextMethodParamIdx]; + // Add any generic substitutions for the base class. + auto baseSelfType = baseCalleeType->getSelfParameter().getType(); + if (auto metatypeType = dyn_cast(baseSelfType)) + baseSelfType = CanType(metatypeType->getInstanceType()); + + auto *baseClassDecl = baseSelfType.getClassOrBoundGenericClass(); + assert(baseClassDecl && "not a class method"); + + if (auto baseClassSig = baseClassDecl->getGenericSignatureOfContext()) { + // Compute the type of the base class, starting from the + // derived class type and the type of the method's self + // parameter. + auto baseClass = derivedClass->getSuperclassForDecl(baseClassDecl, nullptr) + ->getCanonicalType(); + auto baseClassSubs = baseClass->gatherAllSubstitutions(Module, nullptr); + + // Decompose the base class substitutions, adding them to the same + // substitution maps as above. + baseClassSig->getSubstitutionMap(baseClassSubs, subMap, conformanceMap); } - return Subs; + // Build the new substitutions using the base method signature. + auto baseCalleeSig = baseCalleeType->getGenericSignature(); + baseCalleeSig->getSubstitutions(*Module, subMap, conformanceMap, newSubs); } SILFunction *swift::getTargetClassMethod(SILModule &M, @@ -468,6 +364,7 @@ SILFunction *swift::getTargetClassMethod(SILModule &M, /// return true if it is possible to devirtualize, false - otherwise. bool swift::canDevirtualizeClassMethod(FullApplySite AI, SILType ClassOrMetatypeType) { + DEBUG(llvm::dbgs() << " Trying to devirtualize : " << *AI.getInstruction()); SILModule &Mod = AI.getModule(); @@ -515,26 +412,10 @@ bool swift::canDevirtualizeClassMethod(FullApplySite AI, if (GenCalleeType->isPolymorphic()) { // First, find proper list of substitutions for the concrete // method to be called. - auto Subs = getSubstitutionsForCallee(Mod, GenCalleeType, - ClassOrMetatypeType, AI); - - auto GenericSig = GenCalleeType->getGenericSignature(); - // Get the number of expected generic parameters, which - // is a sum of the number of explicit generic parameters - // and the number of their recursive member types exposed - // through protocol requirements. - auto DepTypes = GenericSig->getAllDependentTypes(); - unsigned ExpectedSubsNum = 0; - - for (auto DT: DepTypes) { - (void)DT; - ExpectedSubsNum++; - } - - if (ExpectedSubsNum != Subs.size()) { - return false; - } - + SmallVector Subs; + getSubstitutionsForCallee(Mod, GenCalleeType, + ClassOrMetatypeType.getSwiftRValueType(), + AI, Subs); SubstCalleeType = GenCalleeType->substGenericArgs(Mod, Mod.getSwiftModule(), Subs); } @@ -565,8 +446,10 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI, CanSILFunctionType GenCalleeType = F->getLoweredFunctionType(); - auto Subs = getSubstitutionsForCallee(Mod, GenCalleeType, - ClassOrMetatypeType, AI); + SmallVector Subs; + getSubstitutionsForCallee(Mod, GenCalleeType, + ClassOrMetatypeType.getSwiftRValueType(), + AI, Subs); CanSILFunctionType SubstCalleeType = GenCalleeType; if (GenCalleeType->isPolymorphic()) SubstCalleeType = GenCalleeType->substGenericArgs(Mod, Mod.getSwiftModule(), Subs); @@ -710,66 +593,135 @@ DevirtualizationResult swift::tryDevirtualizeClassMethod(FullApplySite AI, // Witness Method Optimization //===----------------------------------------------------------------------===// +static ArrayRef +getSubstitutionsForProtocolConformance(ProtocolConformanceRef CRef) { + auto C = CRef.getConcrete(); + + // Walk down to the base NormalProtocolConformance. + ArrayRef Subs; + const ProtocolConformance *ParentC = C; + while (!isa(ParentC)) { + switch (ParentC->getKind()) { + case ProtocolConformanceKind::Normal: + llvm_unreachable("should have exited the loop?!"); + case ProtocolConformanceKind::Inherited: + ParentC = cast(ParentC) + ->getInheritedConformance(); + break; + case ProtocolConformanceKind::Specialized: { + auto SC = cast(ParentC); + ParentC = SC->getGenericConformance(); + assert(Subs.empty() && "multiple conformance specializations?!"); + Subs = SC->getGenericSubstitutions(); + break; + } + } + } + const NormalProtocolConformance *NormalC + = cast(ParentC); + + // If the normal conformance is for a generic type, and we didn't hit a + // specialized conformance, collect the substitutions from the generic type. + // FIXME: The AST should do this for us. + if (NormalC->getType()->isSpecialized() && Subs.empty()) { + Subs = NormalC->getType() + ->gatherAllSubstitutions(NormalC->getDeclContext()->getParentModule(), + nullptr); + } + + return Subs; +} + +/// Compute substitutions for making a direct call to a SIL function with +/// @convention(witness_method) convention. +/// +/// Such functions have a substituted generic signature where the +/// abstract `Self` parameter from the original type of the protocol +/// requirement is replaced by a concrete type. +/// +/// Thus, the original substitutions of the apply instruction that +/// are written in terms of the requirement's generic signature need +/// to be remapped to substitutions suitable for the witness signature. +/// +/// \param conformanceRef The (possibly-specialized) conformance +/// \param requirementSig The generic signature of the requirement +/// \param witnessThunkSig The generic signature of the witness method +/// \param origSubs The substitutions from the call instruction +/// \param newSubs New substitutions are stored here +static void getWitnessMethodSubstitutions( + SILModule &M, + ProtocolConformanceRef conformanceRef, + GenericSignature *requirementSig, + GenericSignature *witnessThunkSig, + ArrayRef origSubs, + SmallVectorImpl &newSubs) { + + if (witnessThunkSig == nullptr) + return; + + assert(!conformanceRef.isAbstract()); + + auto conformance = conformanceRef.getConcrete(); + + // Otherwise, we need to build new caller-side substitutions + // written in terms of the witness thunk's generic signature, + // mapping to the archetypes of the caller. + TypeSubstitutionMap subMap; + TypeConformanceMap conformanceMap; + + // Take apart caller-side substitutions. + // + // Note that the Self-derived archetypes appearing on the left + // hand side of the map do not end up being used. + requirementSig->getSubstitutionMap(origSubs, subMap, conformanceMap); + + // Take apart substitutions from the conforming type. + // + // If `Self` maps to a bound generic type, this gives us the + // substitutions for the concrete type's generic parameters. + auto witnessSubs = getSubstitutionsForProtocolConformance(conformanceRef); + + if (!witnessSubs.empty()) { + auto *rootConformance = conformance->getRootNormalConformance(); + auto *witnessSig = rootConformance->getGenericSignature(); + + witnessSig->getSubstitutionMap(witnessSubs, subMap, conformanceMap); + } + + // Now, apply both sets of substitutions computed above to the + // forwarding substitutions of the witness thunk. + witnessThunkSig->getSubstitutions(*M.getSwiftModule(), + subMap, conformanceMap, newSubs); +} + static void getWitnessMethodSubstitutions(ApplySite AI, SILFunction *F, - ArrayRef Subs, + ProtocolConformanceRef CRef, SmallVectorImpl &NewSubs) { auto &Module = AI.getModule(); - auto CalleeCanType = F->getLoweredFunctionType(); - - ProtocolDecl *proto = nullptr; - if (CalleeCanType->getRepresentation() == - SILFunctionTypeRepresentation::WitnessMethod) { - proto = CalleeCanType->getDefaultWitnessMethodProtocol( - *Module.getSwiftModule()); - } + auto requirementSig = AI.getOrigCalleeType()->getGenericSignature(); + auto witnessThunkSig = F->getLoweredFunctionType()->getGenericSignature(); ArrayRef origSubs = AI.getSubstitutions(); - if (proto != nullptr) { - // If the callee is a default witness method thunk, preserve substitutions - // from the call site. + if (F->getLoweredFunctionType()->getRepresentation() + == SILFunctionTypeRepresentation::WitnessMethod && + F->getLoweredFunctionType()->getDefaultWitnessMethodProtocol( + *Module.getSwiftModule())) { + // Default witness thunks use the generic signature of the requirement. NewSubs.append(origSubs.begin(), origSubs.end()); return; } - // If the callee is a concrete witness method thunk, apply substitutions - // from the conformance, and drop any substitutions derived from the Self - // type. - NewSubs.append(Subs.begin(), Subs.end()); - - if (auto generics = AI.getOrigCalleeType()->getGenericSignature()) { - for (auto genericParam : generics->getAllDependentTypes()) { - auto origSub = origSubs.front(); - origSubs = origSubs.slice(1); - - // If the callee is a concrete witness method thunk, we ignore - // generic parameters derived from 'self', the generic parameter at - // depth 0, index 0. - auto type = genericParam->getCanonicalType(); - while (auto memberType = dyn_cast(type)) { - type = memberType.getBase(); - } - auto paramType = cast(type); - if (paramType->getDepth() == 0) { - // There shouldn't be any other parameters at this depth. - assert(paramType->getIndex() == 0); - continue; - } - - // Okay, remember this substitution. - NewSubs.push_back(origSub); - } - } - - assert(origSubs.empty() && "subs not parallel to dependent types"); + getWitnessMethodSubstitutions(Module, CRef, requirementSig, witnessThunkSig, + origSubs, NewSubs); } /// Generate a new apply of a function_ref to replace an apply of a /// witness_method when we've determined the actual function we'll end /// up calling. static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, - ArrayRef Subs) { + ProtocolConformanceRef C) { // We know the witness thunk and the corresponding set of substitutions // required to invoke the protocol method at this point. auto &Module = AI.getModule(); @@ -781,7 +733,7 @@ static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, // additional generic parameters. SmallVector NewSubs; - getWitnessMethodSubstitutions(AI, F, Subs, NewSubs); + getWitnessMethodSubstitutions(AI, F, C, NewSubs); // Figure out the exact bound type of the function to be called by // applying all substitutions. @@ -836,12 +788,11 @@ static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, /// of a function_ref, returning the new apply. DevirtualizationResult swift::tryDevirtualizeWitnessMethod(ApplySite AI) { SILFunction *F; - ArrayRef Subs; SILWitnessTable *WT; auto *WMI = cast(AI.getCallee()); - std::tie(F, WT, Subs) = + std::tie(F, WT) = AI.getModule().lookUpFunctionInWitnessTable(WMI->getConformance(), WMI->getMember()); @@ -855,7 +806,7 @@ DevirtualizationResult swift::tryDevirtualizeWitnessMethod(ApplySite AI) { return std::make_pair(nullptr, FullApplySite()); } - auto Result = devirtualizeWitnessMethod(AI, F, Subs); + auto Result = devirtualizeWitnessMethod(AI, F, WMI->getConformance()); return std::make_pair(Result.getInstruction(), Result); } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index df17a732c5c5b..a2dfa19f3482d 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -114,7 +114,7 @@ Type Solution::computeSubstitutions( } auto lookupConformanceFn = - [&](Type replacement, ProtocolType *protoType) + [&](CanType original, Type replacement, ProtocolType *protoType) -> ProtocolConformanceRef { ProtocolConformance *conformance = nullptr; diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index b91db5c06e00d..1d90dd89fb09f 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -957,15 +957,10 @@ void ConstraintSystem::openGeneric( bool skipProtocolSelfConstraint, ConstraintLocatorBuilder locator, llvm::DenseMap &replacements) { - // Use the minimized constraints; we can re-derive solutions for all the - // implied constraints. - auto minimized = - signature->getCanonicalManglingSignature(*DC->getParentModule()); - openGeneric(innerDC, outerDC, - minimized->getGenericParams(), - minimized->getRequirements(), + signature->getGenericParams(), + signature->getRequirements(), skipProtocolSelfConstraint, locator, replacements); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 3b7492bef1baa..2aaf104e9039b 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -736,7 +736,8 @@ TypeChecker::handleSILGenericParams(GenericParamList *genericParams, revertGenericParamList(genericParams); ArchetypeBuilder builder(*DC->getParentModule(), Diags); - checkGenericParamList(&builder, genericParams, parentSig); + checkGenericParamList(&builder, genericParams, parentSig, parentEnv, + nullptr); parentEnv = finalizeGenericParamList(builder, genericParams, genericSig, DC); parentSig = genericSig; @@ -4720,7 +4721,8 @@ class DeclChecker : public DeclVisitor { ArchetypeBuilder builder = TC.createArchetypeBuilder(FD->getModuleContext()); auto *parentSig = FD->getDeclContext()->getGenericSignatureOfContext(); - TC.checkGenericParamList(&builder, gp, parentSig); + auto *parentEnv = FD->getDeclContext()->getGenericEnvironmentOfContext(); + TC.checkGenericParamList(&builder, gp, parentSig, parentEnv, nullptr); // Infer requirements from parameter patterns. for (auto pattern : FD->getParameterLists()) { @@ -4737,7 +4739,8 @@ class DeclChecker : public DeclVisitor { TC.revertGenericFuncSignature(FD); // Assign archetypes. - auto *env = TC.finalizeGenericParamList(builder, gp, nullptr, FD); + auto *env = TC.finalizeGenericParamList(builder, gp, + FD->getGenericSignature(), FD); FD->setGenericEnvironment(env); } } else if (FD->getDeclContext()->getGenericSignatureOfContext()) { @@ -6410,7 +6413,8 @@ class DeclChecker : public DeclVisitor { ArchetypeBuilder builder = TC.createArchetypeBuilder(CD->getModuleContext()); auto *parentSig = CD->getDeclContext()->getGenericSignatureOfContext(); - TC.checkGenericParamList(&builder, gp, parentSig); + auto *parentEnv = CD->getDeclContext()->getGenericEnvironmentOfContext(); + TC.checkGenericParamList(&builder, gp, parentSig, parentEnv, nullptr); // Infer requirements from the parameters of the constructor. builder.inferRequirements(CD->getParameterList(1), gp); @@ -6420,7 +6424,8 @@ class DeclChecker : public DeclVisitor { TC.revertGenericFuncSignature(CD); // Assign archetypes. - auto *env = TC.finalizeGenericParamList(builder, gp, nullptr, CD); + auto *env = TC.finalizeGenericParamList(builder, gp, + CD->getGenericSignature(), CD); CD->setGenericEnvironment(env); } } else if (CD->getDeclContext()->getGenericSignatureOfContext()) { @@ -7423,9 +7428,13 @@ static Type checkExtensionGenericParams( // Validate the generic type signature. bool invalid = false; + auto *parentSig = ext->getDeclContext()->getGenericSignatureOfContext(); + auto *parentEnv = ext->getDeclContext()->getGenericEnvironmentOfContext(); GenericSignature *sig = tc.validateGenericSignature( - genericParams, ext->getDeclContext(), - nullptr, inferExtendedTypeReqs, invalid); + genericParams, + ext->getDeclContext(), + parentSig, + inferExtendedTypeReqs, invalid); ext->setGenericSignature(sig); if (invalid) { @@ -7437,11 +7446,10 @@ static Type checkExtensionGenericParams( // Validate the generic parameters for the last time. tc.revertGenericParamList(genericParams); ArchetypeBuilder builder = tc.createArchetypeBuilder(ext->getModuleContext()); - auto *parentSig = ext->getDeclContext()->getGenericSignatureOfContext(); - tc.checkGenericParamList(&builder, genericParams, parentSig); + tc.checkGenericParamList(&builder, genericParams, parentSig, parentEnv, nullptr); inferExtendedTypeReqs(builder); - auto *env = tc.finalizeGenericParamList(builder, genericParams, nullptr, ext); + auto *env = tc.finalizeGenericParamList(builder, genericParams, sig, ext); ext->setGenericEnvironment(env); if (isa(nominal)) { diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 53a79640f4440..40518fbe7d868 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -238,14 +238,14 @@ Type CompleteGenericTypeResolver::resolveTypeOfDecl(TypeDecl *decl) { bool TypeChecker::checkGenericParamList(ArchetypeBuilder *builder, GenericParamList *genericParams, GenericSignature *parentSig, - bool adoptArchetypes, + GenericEnvironment *parentEnv, GenericTypeResolver *resolver) { bool invalid = false; // If there is a parent context, add the generic parameters and requirements // from that context. if (builder) - builder->addGenericSignature(parentSig, adoptArchetypes); + builder->addGenericSignature(parentSig, parentEnv); // If there aren't any generic parameters at this level, we're done. if (!genericParams) @@ -389,7 +389,8 @@ static bool checkGenericFuncSignature(TypeChecker &tc, tc.checkGenericParamList(builder, genericParams, func->getDeclContext()->getGenericSignatureOfContext(), - false, &resolver); + nullptr, + &resolver); // Check the parameter patterns. for (auto params : func->getParameterLists()) { @@ -485,9 +486,10 @@ TypeChecker::markInvalidGenericSignature(DeclContext *DC) { auto builder = createArchetypeBuilder(parentDC->getParentModule()); auto parentSig = parentDC->getGenericSignatureOfContext(); + auto parentEnv = parentDC->getGenericEnvironmentOfContext(); if (parentSig != nullptr) - builder.addGenericSignature(parentSig, true); + builder.addGenericSignature(parentSig, parentEnv); // Visit each of the generic parameters. for (auto param : *genericParams) @@ -553,10 +555,6 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) { llvm::errs() << "Canonical generic signature: "; sig->getCanonicalSignature()->print(llvm::errs()); llvm::errs() << "\n"; - llvm::errs() << "Canonical generic signature for mangling: "; - sig->getCanonicalManglingSignature(*func->getParentModule()) - ->print(llvm::errs()); - llvm::errs() << "\n"; } func->setGenericSignature(sig); @@ -711,7 +709,7 @@ void TypeChecker::configureInterfaceType(AbstractFunctionDecl *func) { GenericSignature *TypeChecker::validateGenericSignature( GenericParamList *genericParams, DeclContext *dc, - GenericSignature *outerSignature, + GenericSignature *parentSig, std::function inferRequirements, bool &invalid) { assert(genericParams && "Missing generic parameters?"); @@ -719,15 +717,12 @@ GenericSignature *TypeChecker::validateGenericSignature( // Create the archetype builder. Module *module = dc->getParentModule(); ArchetypeBuilder builder = createArchetypeBuilder(module); - auto *parentSig = (outerSignature - ? outerSignature - : dc->getGenericSignatureOfContext()); // Type check the generic parameters, treating all generic type // parameters as dependent, unresolved. DependentGenericTypeResolver dependentResolver(builder); if (checkGenericParamList(&builder, genericParams, parentSig, - false, &dependentResolver)) { + nullptr, &dependentResolver)) { invalid = true; } @@ -744,8 +739,8 @@ GenericSignature *TypeChecker::validateGenericSignature( // and type-check it again, completely. revertGenericParamList(genericParams); CompleteGenericTypeResolver completeResolver(*this, builder); - if (checkGenericParamList(nullptr, genericParams, parentSig, - false, &completeResolver)) { + if (checkGenericParamList(nullptr, genericParams, nullptr, + nullptr, &completeResolver)) { invalid = true; } @@ -768,10 +763,6 @@ GenericSignature *TypeChecker::validateGenericSignature( llvm::errs() << "Canonical generic signature: "; sig->getCanonicalSignature()->print(llvm::errs()); llvm::errs() << "\n"; - llvm::errs() << "Canonical generic signature for mangling: "; - sig->getCanonicalManglingSignature(*dc->getParentModule()) - ->print(llvm::errs()); - llvm::errs() << "\n"; } return sig; @@ -807,8 +798,6 @@ TypeChecker::finalizeGenericParamList(ArchetypeBuilder &builder, access = std::max(access, Accessibility::Internal); // Wire up the archetypes. - if (genericSig == nullptr) - genericSig = dc->getGenericSignatureOfContext(); auto genericEnv = builder.getGenericEnvironment( genericSig->getGenericParams()); @@ -913,7 +902,8 @@ bool TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { auto *gp = typeDecl->getGenericParams(); auto *dc = typeDecl->getDeclContext(); - auto *sig = validateGenericSignature(gp, dc, nullptr, nullptr, invalid); + auto *sig = validateGenericSignature(gp, dc, dc->getGenericSignatureOfContext(), + nullptr, invalid); assert(sig->getInnermostGenericParams().size() == typeDecl->getGenericParams()->size()); typeDecl->setGenericSignature(sig); @@ -929,9 +919,10 @@ bool TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { ArchetypeBuilder builder = createArchetypeBuilder(typeDecl->getModuleContext()); auto *parentSig = dc->getGenericSignatureOfContext(); - checkGenericParamList(&builder, gp, parentSig); + auto *parentEnv = dc->getGenericEnvironmentOfContext(); + checkGenericParamList(&builder, gp, parentSig, parentEnv, nullptr); - auto *env = finalizeGenericParamList(builder, gp, nullptr, typeDecl); + auto *env = finalizeGenericParamList(builder, gp, sig, typeDecl); typeDecl->setGenericEnvironment(env); return invalid; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 044e35bd5e497..065a753cd6c62 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -45,6 +45,7 @@ namespace { TypeChecker &TC; ProtocolDecl *Proto; Type Adoptee; + // The conforming context, either a nominal type or extension. DeclContext *DC; WitnessChecker(TypeChecker &tc, ProtocolDecl *proto, @@ -1334,16 +1335,19 @@ namespace { /// /// This class evaluates true if an error occurred. class CheckTypeWitnessResult { - ProtocolDecl *Proto = nullptr; + NominalTypeDecl *Nominal = nullptr; public: CheckTypeWitnessResult() { } - CheckTypeWitnessResult(ProtocolDecl *proto) : Proto(proto) { } + CheckTypeWitnessResult(NominalTypeDecl *nominal) : Nominal(nominal) { + assert(isa(nominal) || isa(nominal)); + } - ProtocolDecl *getProtocol() const { return Proto; } + NominalTypeDecl *getProtocolOrClass() const { return Nominal; } + bool isProtocol() const { return isa(Nominal); } - explicit operator bool() const { return Proto != nullptr; } + explicit operator bool() const { return Nominal != nullptr; } }; /// The set of associated types that have been inferred by matching @@ -1412,13 +1416,8 @@ namespace { /// \param type The witness type. /// /// \param typeDecl The decl the witness type came from; can be null. - /// - /// \param fromDC The DeclContext from which this associated type was - /// computed, which may be different from the context associated with the - /// protocol conformance. void recordTypeWitness(AssociatedTypeDecl *assocType, Type type, - TypeDecl *typeDecl, DeclContext *fromDC, - bool performRedeclarationCheck); + TypeDecl *typeDecl, bool performRedeclarationCheck); /// Resolve a (non-type) witness via name lookup. ResolveWitnessResult resolveWitnessViaLookup(ValueDecl *requirement); @@ -1463,6 +1462,8 @@ namespace { ValueDecl *requirement, bool isError, std::function fn); + void addUsedConformances(ProtocolConformance *conformance); + public: /// Emit any diagnostics that have been delayed. void emitDelayedDiags(); @@ -1889,7 +1890,6 @@ void ConformanceChecker::recordOptionalWitness(ValueDecl *requirement) { void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType, Type type, TypeDecl *typeDecl, - DeclContext *fromDC, bool performRedeclarationCheck) { // If we already recoded this type witness, there's nothing to do. @@ -2498,7 +2498,10 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault( static CheckTypeWitnessResult checkTypeWitness(TypeChecker &tc, DeclContext *dc, AssociatedTypeDecl *assocType, Type type) { - // FIXME: Check class requirement. + if (auto superclass = assocType->getSuperclass()) { + if (!superclass->isExactSuperclassOf(type, &tc)) + return superclass->getAnyNominal(); + } // Check protocol conformances. for (auto reqProto : assocType->getConformingProtocols(&tc)) { @@ -2524,12 +2527,12 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( // Determine which of the candidates is viable. SmallVector, 2> viable; - SmallVector, 2> nonViable; + SmallVector, 2> nonViable; for (auto candidate : candidates) { // Check this type against the protocol requirements. if (auto checkResult = checkTypeWitness(TC, DC, assocType, candidate.second)) { - auto reqProto = checkResult.getProtocol(); + auto reqProto = checkResult.getProtocolOrClass(); nonViable.push_back({candidate.first, reqProto}); } else { viable.push_back(candidate); @@ -2538,13 +2541,12 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( // If there is a single viable candidate, form a substitution for it. if (viable.size() == 1) { - recordTypeWitness(assocType, viable.front().second, viable.front().first, - viable.front().first->getDeclContext(), true); + recordTypeWitness(assocType, viable.front().second, viable.front().first, true); return ResolveWitnessResult::Success; } // Record an error. - recordTypeWitness(assocType, ErrorType::get(TC.Context), nullptr, DC, false); + recordTypeWitness(assocType, ErrorType::get(TC.Context), nullptr, false); // If we had multiple viable types, diagnose the ambiguity. if (!viable.empty()) { @@ -2575,7 +2577,8 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup( tc.diagnose(candidate.first, diag::protocol_witness_nonconform_type, candidate.first->getDeclaredType(), - candidate.second->getDeclaredType()); + candidate.second->getDeclaredType(), + candidate.second->getDeclaredType()->is()); } }); @@ -3406,8 +3409,7 @@ void ConformanceChecker::resolveTypeWitnesses() { auto &typeWitnesses = solutions.front().TypeWitnesses; for (auto assocType : unresolvedAssocTypes) { assert(typeWitnesses.count(assocType) == 1 && "missing witness"); - recordTypeWitness(assocType, typeWitnesses[assocType].first, nullptr, DC, - true); + recordTypeWitness(assocType, typeWitnesses[assocType].first, nullptr, true); } return; @@ -3419,7 +3421,7 @@ void ConformanceChecker::resolveTypeWitnesses() { // We're going to produce an error below. Mark each unresolved // associated type witness as erroneous. for (auto assocType : unresolvedAssocTypes) { - recordTypeWitness(assocType, ErrorType::get(TC.Context), nullptr, DC, true); + recordTypeWitness(assocType, ErrorType::get(TC.Context), nullptr, true); } // No solutions. Diagnose the first associated type for which we @@ -3437,7 +3439,8 @@ void ConformanceChecker::resolveTypeWitnesses() { failedDefaultedWitness, failedDefaultedAssocType->getFullName(), proto->getDeclaredType(), - failedDefaultedResult.getProtocol()->getDeclaredType()); + failedDefaultedResult.getProtocolOrClass()->getDeclaredType(), + failedDefaultedResult.isProtocol()); }); return; } @@ -3475,7 +3478,8 @@ void ConformanceChecker::resolveTypeWitnesses() { diag::associated_type_deduction_witness_failed, failed.Requirement->getFullName(), failed.TypeWitness, - failed.Result.getProtocol()->getFullName()); + failed.Result.getProtocolOrClass()->getFullName(), + failed.Result.isProtocol()); } }); @@ -3691,6 +3695,53 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) { } } +static void recordConformanceDependency(DeclContext *DC, + NominalTypeDecl *Adoptee, + ProtocolConformance *Conformance, + bool InExpression) { + if (!Conformance) + return; + + auto *topLevelContext = DC->getModuleScopeContext(); + auto *SF = dyn_cast(topLevelContext); + if (!SF) + return; + + auto *tracker = SF->getReferencedNameTracker(); + if (!tracker) + return; + + if (SF->getParentModule() != + Conformance->getDeclContext()->getParentModule()) + return; + + auto &Context = DC->getASTContext(); + + // FIXME: 'deinit' is being used as a dummy identifier here. Really we + // don't care about /any/ of the type's members, only that it conforms to + // the protocol. + tracker->addUsedMember({Adoptee, Context.Id_deinit}, + DC->isCascadingContextForLookup(InExpression)); +} + +void ConformanceChecker::addUsedConformances(ProtocolConformance *conformance) { + auto normalConf = conformance->getRootNormalConformance(); + + if (normalConf->isIncomplete()) + TC.UsedConformances.insert(normalConf); + + // Mark each type witness conformance as used. + conformance->forEachTypeWitness(nullptr, [&](AssociatedTypeDecl *assocType, + Substitution sub, + TypeDecl *witness) -> bool { + for (auto nestedConformance : sub.getConformances()) + if (nestedConformance.isConcrete()) + addUsedConformances(nestedConformance.getConcrete()); + + return false; + }); +} + #pragma mark Protocol conformance checking void ConformanceChecker::checkConformance() { assert(!Conformance->isComplete() && "Conformance is already complete"); @@ -3706,6 +3757,12 @@ void ConformanceChecker::checkConformance() { // Resolve all of the type witnesses. resolveTypeWitnesses(); + // Ensure the conforming type is used. + // + // FIXME: This feels like the wrong place for this, but if we don't put + // it here, extensions don't end up depending on the extended type. + recordConformanceDependency(DC, Adoptee->getAnyNominal(), Conformance, false); + // If we complain about any associated types, there is no point in continuing. // FIXME: Not really true. We could check witnesses that don't involve the // failed associated types. @@ -3714,19 +3771,8 @@ void ConformanceChecker::checkConformance() { return; } - // Ensure that all of the requirements of the protocol have been satisfied. - // Note: the odd check for one generic parameter copes with - // protocols nested within other generic contexts, which is ill-formed. - SourceLoc noteLoc = Proto->getLoc(); - if (noteLoc.isInvalid()) - noteLoc = Loc; - if (Proto->getGenericSignature()->getGenericParams().size() != 1 || - TC.checkGenericArguments(DC, Loc, noteLoc, Proto->getDeclaredType(), - Proto->getGenericSignature(), - {Adoptee})) { - Conformance->setInvalid(); - return; - } + // Ensure the associated type conformances are used. + addUsedConformances(Conformance); // Check non-type requirements. for (auto member : Proto->getMembers()) { @@ -4161,38 +4207,14 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, SourceLoc ComplainLoc) { bool InExpression = options.contains(ConformanceCheckFlags::InExpression); - const DeclContext *topLevelContext = DC->getModuleScopeContext(); auto recordDependency = [=](ProtocolConformance *conformance = nullptr) { - if (options.contains(ConformanceCheckFlags::SuppressDependencyTracking)) - return; - - // Record that we depend on the type's conformance. - auto *constSF = dyn_cast(topLevelContext); - if (!constSF) - return; - auto *SF = const_cast(constSF); - - auto *tracker = SF->getReferencedNameTracker(); - if (!tracker) - return; - - // We only care about intra-module dependencies. - if (conformance) - if (SF->getParentModule() != - conformance->getDeclContext()->getParentModule()) - return; - - if (auto nominal = T->getAnyNominal()) { - // FIXME: 'deinit' is being used as a dummy identifier here. Really we - // don't care about /any/ of the type's members, only that it conforms to - // the protocol. - tracker->addUsedMember({nominal, Context.Id_deinit}, - DC->isCascadingContextForLookup(InExpression)); - } + if (!options.contains(ConformanceCheckFlags::SuppressDependencyTracking)) + if (auto nominal = T->getAnyNominal()) + recordConformanceDependency(DC, nominal, conformance, InExpression); }; // Look up conformance in the module. - Module *M = topLevelContext->getParentModule(); + Module *M = DC->getParentModule(); auto lookupResult = M->lookupConformance(T, Proto, this); if (!lookupResult) { if (ComplainLoc.isValid()) @@ -4211,7 +4233,7 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, } else { if (Conformance) *Conformance = nullptr; - recordDependency(nullptr); + recordDependency(); } // If we're using this conformance, note that. @@ -4229,33 +4251,15 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, if (auto sf = DC->getParentSourceFile()) { sf->addUsedConformance(normalConf); } - - // Hack: If we've used a conformance to the _BridgedStoredNSError - // protocol, also use the RawRepresentable and _ErrorCodeProtocol - // conformances on the Code associated type witness. - if (Proto->isSpecificProtocol(KnownProtocolKind::BridgedStoredNSError)) { - if (auto codeType = ProtocolConformance::getTypeWitnessByName( - T, concrete, Context.Id_Code, this)) { - if (codeType->getAnyNominal() != T->getAnyNominal()) { - if (auto codeProto = - Context.getProtocol(KnownProtocolKind::ErrorCodeProtocol)){ - (void)conformsToProtocol(codeType, codeProto, DC, options, nullptr, - SourceLoc()); - } - - if (auto rawProto = - Context.getProtocol(KnownProtocolKind::RawRepresentable)) { - (void)conformsToProtocol(codeType, rawProto, DC, options, nullptr, - SourceLoc()); - } - } - } - } } return true; } /// Mark any _ObjectiveCBridgeable conformances in the given type as "used". +/// +/// These conformances might not appear in any substitution lists produced +/// by Sema, since bridging is done at the SILGen level, so we have to +/// force them here to ensure SILGen can find them. void TypeChecker::useObjectiveCBridgeableConformances(DeclContext *dc, Type type) { class Walker : public TypeWalker { @@ -4277,6 +4281,8 @@ void TypeChecker::useObjectiveCBridgeableConformances(DeclContext *dc, if (auto *nominalDecl = ty->getAnyNominal()) { (void)TC.conformsToProtocol(ty, Proto, DC, options); + // Set and Dictionary bridging also requires the conformance + // of the key type to Hashable. if (nominalDecl == TC.Context.getSetDecl() || nominalDecl == TC.Context.getDictionaryDecl()) { auto args = ty->castTo()->getGenericArgs(); @@ -4320,32 +4326,44 @@ void TypeChecker::useObjectiveCBridgeableConformancesOfArgs( } void TypeChecker::useBridgedNSErrorConformances(DeclContext *dc, Type type) { + auto bridgedStoredNSError = Context.getProtocol( + KnownProtocolKind::BridgedStoredNSError); + auto errorCodeProto = Context.getProtocol( + KnownProtocolKind::ErrorCodeProtocol); + auto rawProto = Context.getProtocol( + KnownProtocolKind::RawRepresentable); + + if (!bridgedStoredNSError || !errorCodeProto || !rawProto) + return; + // _BridgedStoredNSError. - if (auto bridgedStoredNSError = Context.getProtocol( - KnownProtocolKind::BridgedStoredNSError)) { - // Force it as "Used", if it conforms - if (conformsToProtocol(type, bridgedStoredNSError, dc, - ConformanceCheckFlags::Used)) - return; + ProtocolConformance *conformance = nullptr; + if (conformsToProtocol(type, bridgedStoredNSError, dc, + ConformanceCheckFlags::Used, + &conformance) && + conformance) { + // Hack: If we've used a conformance to the _BridgedStoredNSError + // protocol, also use the RawRepresentable and _ErrorCodeProtocol + // conformances on the Code associated type witness. + if (auto codeType = ProtocolConformance::getTypeWitnessByName( + type, conformance, Context.Id_Code, this)) { + (void)conformsToProtocol(codeType, errorCodeProto, dc, + ConformanceCheckFlags::Used); + (void)conformsToProtocol(codeType, rawProto, dc, + ConformanceCheckFlags::Used); + } } // _ErrorCodeProtocol. - if (auto errorCodeProto = Context.getProtocol( - KnownProtocolKind::ErrorCodeProtocol)) { - ProtocolConformance *conformance = nullptr; - if (conformsToProtocol(type, errorCodeProto, dc, - (ConformanceCheckFlags::SuppressDependencyTracking| - ConformanceCheckFlags::Used), - &conformance) && - conformance) { - if (Type errorType = ProtocolConformance::getTypeWitnessByName( - type, conformance, Context.Id_ErrorType, this)) { - // Early-exit in case of circularity. - if (errorType->getAnyNominal() == type->getAnyNominal()) return; - - useBridgedNSErrorConformances(dc, errorType); - return; - } + if (conformsToProtocol(type, errorCodeProto, dc, + (ConformanceCheckFlags::SuppressDependencyTracking| + ConformanceCheckFlags::Used), + &conformance) && + conformance) { + if (Type errorType = ProtocolConformance::getTypeWitnessByName( + type, conformance, Context.Id_ErrorType, this)) { + (void) conformsToProtocol(errorType, bridgedStoredNSError, dc, + ConformanceCheckFlags::Used); } } } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 05b146a52f626..61efe29e8c007 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1062,8 +1062,8 @@ class TypeChecker final : public LazyResolver { bool checkGenericParamList(ArchetypeBuilder *builder, GenericParamList *genericParams, GenericSignature *parentSig, - bool adoptArchetypes = true, - GenericTypeResolver *resolver = nullptr); + GenericEnvironment *parentEnv, + GenericTypeResolver *resolver); /// Check the given set of generic arguments against the requirements in a /// generic signature. diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift index e80d209b9783a..225563eaec12d 100644 --- a/test/Generics/associated_type_typo.swift +++ b/test/Generics/associated_type_typo.swift @@ -41,8 +41,10 @@ func typoAssoc4(_: T) where T.Assocp2.assoc : P3 {} // CHECK-GENERIC-NEXT: T : P2 [explicit // CHECK-GENERIC-NEXT: T[.P2].AssocP2 witness marker // CHECK-GENERIC-NEXT: T[.P2].AssocP2 : P1 [protocol +// CHECK-GENERIC-NEXT: T[.P2].AssocP2 == T.AssocP2 [redundant] // CHECK-GENERIC-NEXT: T[.P2].AssocP2[.P1].Assoc witness marker // CHECK-GENERIC-NEXT: T[.P2].AssocP2[.P1].Assoc : P3 [explicit +// CHECK-GENERIC-NEXT: T[.P2].AssocP2[.P1].Assoc == T[.P2].AssocP2.Assoc [redundant] // CHECK-GENERIC-NEXT: Generic signature diff --git a/test/Generics/associated_types_inherit.swift b/test/Generics/associated_types_inherit.swift index 65587c5d79ea7..4a569c4c6eca6 100644 --- a/test/Generics/associated_types_inherit.swift +++ b/test/Generics/associated_types_inherit.swift @@ -9,8 +9,8 @@ class D : C { class E { } -protocol P { // expected-note{{requirement specified as 'Self.Assoc' : 'C' [with Self = X2]}} - associatedtype Assoc : C +protocol P { + associatedtype Assoc : C // expected-note{{unable to infer associated type 'Assoc' for protocol 'P'}} func getAssoc() -> Assoc } @@ -18,8 +18,8 @@ struct X1 : P { func getAssoc() -> D { return D() } } -struct X2 : P { // expected-error{{'P' requires that 'E' inherit from 'C'}} - func getAssoc() -> E { return E() } +struct X2 : P { // expected-error{{type 'X2' does not conform to protocol 'P'}} + func getAssoc() -> E { return E() } // expected-note{{inferred type 'E' (by matching requirement 'getAssoc()') is invalid: does not inherit from 'C'}} } func testP(_ t: T) { diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift index 19e3c787fe37d..88322e000fb48 100644 --- a/test/Generics/requirement_inference.swift +++ b/test/Generics/requirement_inference.swift @@ -119,9 +119,9 @@ struct Model_P3_P4_Eq where T.P3Assoc == U.P4Assoc {} // CHECK-NEXT: U witness marker // CHECK-NEXT: U : P4 [inferred @ {{.*}}:32] // CHECK-NEXT: T[.P3].P3Assoc witness marker -// CHECK-NEXT: T[.P3].P3Assoc : P1 [protocol @ {{.*}}:18] +// CHECK-NEXT: T[.P3].P3Assoc : P1 [redundant @ {{.*}}:18] // CHECK-NEXT: T[.P3].P3Assoc : P2 [protocol @ {{.*}}:18] -// CHECK-NEXT: U[.P4].P4Assoc == T[.P3].P3Assoc [inferred @ {{.*}}32] +// CHECK-NEXT: T[.P3].P3Assoc == U[.P4].P4Assoc [inferred @ {{.*}}32] func inferSameType1(_ x: Model_P3_P4_Eq) { } // CHECK-LABEL: .inferSameType2@ @@ -131,9 +131,9 @@ func inferSameType1(_ x: Model_P3_P4_Eq) { } // CHECK-NEXT: U witness marker // CHECK-NEXT: U : P4 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:33] // CHECK-NEXT: T[.P3].P3Assoc witness marker -// CHECK-NEXT: T[.P3].P3Assoc : P1 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:18] -// CHECK-NEXT: T[.P3].P3Assoc : P2 [redundant @ {{.*}}requirement_inference.swift:{{.*}}:61] -// CHECK-NEXT: U[.P4].P4Assoc == T[.P3].P3Assoc [explicit @ {{.*}}requirement_inference.swift:{{.*}}:75] +// CHECK-NEXT: T[.P3].P3Assoc : P1 [redundant @ {{.*}}requirement_inference.swift:{{.*}}:18] +// CHECK-NEXT: T[.P3].P3Assoc : P2 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:18] +// CHECK-NEXT: T[.P3].P3Assoc == U[.P4].P4Assoc [explicit @ {{.*}}requirement_inference.swift:{{.*}}:75] func inferSameType2(_: T) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {} // CHECK-LABEL: .inferSameType3@ @@ -143,7 +143,7 @@ func inferSameType2(_: T) where U.P4Assoc : P2, T.P3Assoc == U.P // CHECK-NEXT: T : PCommonAssoc2 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:76] // CHECK-NEXT: T[.PCommonAssoc1].CommonAssoc witness marker // CHECK-NEXT: T[.PCommonAssoc1].CommonAssoc : P1 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:68] -// CHECK-NEXT: T[.PCommonAssoc2].CommonAssoc == T[.PCommonAssoc1].CommonAssoc [inferred @ {{.*}}requirement_inference.swift:{{.*}}:76] +// CHECK-NEXT: T[.PCommonAssoc1].CommonAssoc == T[.PCommonAssoc2].CommonAssoc [redundant @ {{.*}}requirement_inference.swift:{{.*}}:76] // CHECK-NEXT: Generic signature func inferSameType3(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {} @@ -160,7 +160,7 @@ protocol P7 : P6 { } // CHECK-LABEL: P7.nestedSameType1()@ -// CHECK: Canonical generic signature for mangling: <τ_0_0 where τ_0_0 : P7, τ_0_0.AssocP6.Element : P6, τ_0_0.AssocP6.Element == τ_0_0.AssocP7.AssocP6.Element> +// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P7, τ_0_0.AssocP6.Element : P6, τ_0_0.AssocP6.Element == τ_0_0.AssocP7.AssocP6.Element> extension P7 where AssocP6.Element : P6, AssocP7.AssocP6.Element : P6, AssocP6.Element == AssocP7.AssocP6.Element { diff --git a/test/Generics/superclass_constraint.swift b/test/Generics/superclass_constraint.swift index 6e5a18fa65a06..bad766779731f 100644 --- a/test/Generics/superclass_constraint.swift +++ b/test/Generics/superclass_constraint.swift @@ -57,8 +57,8 @@ class S : P2 { extension P2 where Self.T : C { // CHECK: superclass_constraint.(file).P2.concreteTypeWitnessViaSuperclass1 - // CHECK: Generic signature: - // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P2, τ_0_0.T : C, τ_0_0.T : P3, τ_0_0.T.T == Int> + // CHECK: Generic signature: + // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P2, τ_0_0.T : C> func concreteTypeWitnessViaSuperclass1(x: Self.T.T) {} } @@ -67,8 +67,8 @@ extension P2 where Self.T : C { // CHECK-NEXT: T witness marker // CHECK-NEXT: T : C [explicit @ // CHECK-NEXT: T : P3 [redundant @ -// CHECK-NEXT: T[.P3].T == C.T [protocol] -// CHECK: Canonical generic signature for mangling: <τ_0_0 where τ_0_0 : C> +// CHECK-NEXT: T[.P3].T == C.T [redundant] +// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C> func superclassConformance1(t: T) where T : C, T : P3 {} // CHECK: superclassConformance2 @@ -76,8 +76,8 @@ func superclassConformance1(t: T) where T : C, T : P3 {} // CHECK-NEXT: T witness marker // CHECK-NEXT: T : C [explicit @ // CHECK-NEXT: T : P3 [redundant @ -// CHECK-NEXT: T[.P3].T == C.T [protocol] -// CHECK: Canonical generic signature for mangling: <τ_0_0 where τ_0_0 : C> +// CHECK-NEXT: T[.P3].T == C.T [redundant] +// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C> func superclassConformance2(t: T) where T : C, T : P3 {} protocol P4 { } @@ -89,5 +89,5 @@ class C2 : C, P4 { } // CHECK-NEXT: T witness marker // CHECK-NEXT: T : C2 [explicit @ // CHECK-NEXT: T : P4 [redundant @ -// CHECK: Canonical generic signature for mangling: <τ_0_0 where τ_0_0 : C2> +// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C2> func superclassConformance3(t: T) where T : C, T : P4, T : C2 {} diff --git a/test/NameBinding/reference-dependencies.swift b/test/NameBinding/reference-dependencies.swift index 4857b48884463..d19c55afecaef 100644 --- a/test/NameBinding/reference-dependencies.swift +++ b/test/NameBinding/reference-dependencies.swift @@ -419,7 +419,6 @@ struct Sentinel2 {} // CHECK-DAG: - !private ["VV4main26OtherFileSecretTypeWrapper10SecretType", "constant"] // CHECK-DAG: - !private ["V4main25OtherFileProtoImplementor", "deinit"] // CHECK-DAG: - !private ["V4main26OtherFileProtoImplementor2", "deinit"] -// CHECK-DAG: - !private ["V4main28OtherFileProtoNonImplementor", "deinit"] // CHECK-DAG: - !private ["Vs13EmptyIterator", "Element"] // CHECK-DAG: - !private ["Vs13EmptyIterator", "init"] // CHECK-DAG: - !private ["Vs16IndexingIterator", "Element"] @@ -459,7 +458,6 @@ struct Sentinel2 {} // CHECK-DAG: !private "VV4main26OtherFileSecretTypeWrapper10SecretType" // CHECK-DAG: !private "V4main25OtherFileProtoImplementor" // CHECK-DAG: !private "V4main26OtherFileProtoImplementor2" -// CHECK-DAG: !private "V4main28OtherFileProtoNonImplementor" // CHECK-DAG: !private "Vs13EmptyIterator" // CHECK-DAG: !private "Vs16IndexingIterator" // CHECK-DAG: - "O4main13OtherFileEnum" diff --git a/test/SIL/Parser/default_witness_tables.sil b/test/SIL/Parser/default_witness_tables.sil index cfe23f6a07375..f1ffd3fb24956 100644 --- a/test/SIL/Parser/default_witness_tables.sil +++ b/test/SIL/Parser/default_witness_tables.sil @@ -14,7 +14,7 @@ public protocol ResilientProtocol { func defaultE() } -// CHECK-LABEL: sil @defaultC : $@convention(witness_method) <`Self` where `Self` : ResilientProtocol, `Self`.T : Proto> (@in_guaranteed `Self`) -> () +// CHECK-LABEL: sil @defaultC : $@convention(witness_method) <`Self` where `Self` : ResilientProtocol> (@in_guaranteed `Self`) -> () sil @defaultC : $@convention(witness_method) (@in_guaranteed Self) -> () { bb0(%0 : $*Self): %result = tuple () @@ -22,7 +22,7 @@ bb0(%0 : $*Self): } -// CHECK-LABEL: sil @defaultD : $@convention(witness_method) <`Self` where `Self` : ResilientProtocol, `Self`.T : Proto> (@in_guaranteed `Self`) -> () +// CHECK-LABEL: sil @defaultD : $@convention(witness_method) <`Self` where `Self` : ResilientProtocol> (@in_guaranteed `Self`) -> () sil @defaultD : $@convention(witness_method) (@in_guaranteed Self) -> () { bb0(%0 : $*Self): %result = tuple () diff --git a/test/SIL/Parser/generic_signature_with_depth.swift b/test/SIL/Parser/generic_signature_with_depth.swift index e6635aee2ad88..34dec2f714e02 100644 --- a/test/SIL/Parser/generic_signature_with_depth.swift +++ b/test/SIL/Parser/generic_signature_with_depth.swift @@ -18,9 +18,9 @@ protocol mmExt : mmCollectionType { > (_ seq: S) } -// CHECK-LABEL: @_TF28generic_signature_with_depth4testu0_RxS_5mmExt_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) (@in EC1, @in EC2) -> @out EC1 { -// CHECK: witness_method $EC1, #mmExt.extend!1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : mmExt, τ_0_0.Generator : mmGeneratorType><τ_1_0 where τ_1_0 : mmSequenceType, τ_1_0.Generator : mmGeneratorType, τ_1_0.Generator.Element == τ_0_0.Generator.Element> (@in τ_1_0, @inout τ_0_0) -> () -// CHECK: apply {{%[0-9]+}}({{%[0-9]+}}, {{%[0-9]+}}) : $@convention(witness_method) <τ_0_0 where τ_0_0 : mmExt, τ_0_0.Generator : mmGeneratorType><τ_1_0 where τ_1_0 : mmSequenceType, τ_1_0.Generator : mmGeneratorType, τ_1_0.Generator.Element == τ_0_0.Generator.Element> (@in τ_1_0, @inout τ_0_0) -> () +// CHECK-LABEL: @_TF28generic_signature_with_depth4testu0_RxS_5mmExt_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) (@in EC1, @in EC2) -> @out EC1 { +// CHECK: witness_method $EC1, #mmExt.extend!1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : mmExt><τ_1_0 where τ_1_0 : mmSequenceType, τ_0_0.Generator.Element == τ_1_0.Generator.Element> (@in τ_1_0, @inout τ_0_0) -> () +// CHECK: apply {{%[0-9]+}}({{%[0-9]+}}, {{%[0-9]+}}) : $@convention(witness_method) <τ_0_0 where τ_0_0 : mmExt><τ_1_0 where τ_1_0 : mmSequenceType, τ_0_0.Generator.Element == τ_1_0.Generator.Element> (@in τ_1_0, @inout τ_0_0) -> () func test< EC1 : mmExt, diff --git a/test/SIL/Serialization/deserialize_generic_marker.sil b/test/SIL/Serialization/deserialize_generic_marker.sil index 92a6a869f3059..692425b45c8b8 100644 --- a/test/SIL/Serialization/deserialize_generic_marker.sil +++ b/test/SIL/Serialization/deserialize_generic_marker.sil @@ -11,14 +11,14 @@ import Builtin import Swift // CHECK-LABEL: sil @top_level_code -// CHECK: function_ref @_TF18def_generic_marker4testu0_RxS_16mmCollectionType_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : mmCollectionType, τ_0_1 : mmCollectionType, τ_0_0.Generator : mmGeneratorType, τ_0_1.Generator : mmGeneratorType, τ_0_0.Generator.Element == τ_0_1.Generator.Element> (@in τ_0_0, @in τ_0_1) -> @out τ_0_0 +// CHECK: function_ref @_TF18def_generic_marker4testu0_RxS_16mmCollectionType_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : mmCollectionType, τ_0_1 : mmCollectionType, τ_0_0.Generator.Element == τ_0_1.Generator.Element> (@in τ_0_0, @in τ_0_1) -> @out τ_0_0 sil @top_level_code : $@convention(thin) () -> () { bb0: - %43 = function_ref @_TF18def_generic_marker4testu0_RxS_16mmCollectionType_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) (@in EC1, @in EC2) -> @out EC1 + %43 = function_ref @_TF18def_generic_marker4testu0_RxS_16mmCollectionType_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) (@in EC1, @in EC2) -> @out EC1 %0 = tuple () return %0 : $() } // Make sure the function body is deserialized. -// CHECK-LABEL: @_TF18def_generic_marker4testu0_RxS_16mmCollectionType_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) (@in EC1, @in EC2) -> @out EC1 { -sil @_TF18def_generic_marker4testu0_RxS_16mmCollectionType_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) (@in EC1, @in EC2) -> @out EC1 +// CHECK-LABEL: @_TF18def_generic_marker4testu0_RxS_16mmCollectionType_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) (@in EC1, @in EC2) -> @out EC1 { +sil @_TF18def_generic_marker4testu0_RxS_16mmCollectionType_S0_Wx9Generator7Element_zW_S1_S2__rFTxq__x : $@convention(thin) (@in EC1, @in EC2) -> @out EC1 diff --git a/test/SILGen/default_arguments_generic.swift b/test/SILGen/default_arguments_generic.swift index d2d9c48fdccff..59768ac72ec8c 100644 --- a/test/SILGen/default_arguments_generic.swift +++ b/test/SILGen/default_arguments_generic.swift @@ -19,11 +19,11 @@ func bar() { // CHECK: apply [[ZIM_DFLT]] Zim.zim() // CHECK: [[ZANG_DFLT_0:%.*]] = function_ref @_TIZFV25default_arguments_generic3Zim4zang - // CHECK: apply [[ZANG_DFLT_0]] + // CHECK: apply [[ZANG_DFLT_0]] // CHECK: [[ZANG_DFLT_1:%.*]] = function_ref @_TIZFV25default_arguments_generic3Zim4zang - // CHECK: apply [[ZANG_DFLT_1]] + // CHECK: apply [[ZANG_DFLT_1]] Zim.zang() // CHECK: [[ZANG_DFLT_1:%.*]] = function_ref @_TIZFV25default_arguments_generic3Zim4zang - // CHECK: apply [[ZANG_DFLT_1]] + // CHECK: apply [[ZANG_DFLT_1]] Zim.zang(22) } diff --git a/test/SILGen/errors.swift b/test/SILGen/errors.swift index 7951a75fb8d3e..b1a831881000b 100644 --- a/test/SILGen/errors.swift +++ b/test/SILGen/errors.swift @@ -491,7 +491,7 @@ protocol Buildable { func supportFirstStructure(_ b: inout B) throws { try b.firstStructure.support() } -// CHECK-LABEL: sil hidden @_TF6errors21supportFirstStructure{{.*}} : $@convention(thin) (@inout B) -> @error Error { +// CHECK-LABEL: sil hidden @_TF6errors21supportFirstStructure{{.*}} : $@convention(thin) (@inout B) -> @error Error { // CHECK: [[SUPPORT:%.*]] = witness_method $B.Structure, #Supportable.support!1 : // CHECK: [[MATBUFFER:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer // CHECK: [[BUFFER:%.*]] = alloc_stack $B.Structure diff --git a/test/SILGen/generic_literals.swift b/test/SILGen/generic_literals.swift index fc780d0a8cc84..3dbca139c9aec 100644 --- a/test/SILGen/generic_literals.swift +++ b/test/SILGen/generic_literals.swift @@ -11,7 +11,7 @@ func genericIntegerLiteral(x: T) { // CHECK: [[LITVAR:%.*]] = alloc_stack $T.IntegerLiteralType // CHECK: [[LIT:%.*]] = apply [[BUILTINCONV]]([[LITVAR]], [[INTLIT]], [[LITMETA]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : _ExpressibleByBuiltinIntegerLiteral> (Builtin.Int2048, @thick τ_0_0.Type) -> @out τ_0_0 // CHECK: [[ADDR:%.*]] = alloc_stack $T - // CHECK: apply [[TCONV]]([[ADDR]], [[LITVAR]], [[TMETA]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : ExpressibleByIntegerLiteral, τ_0_0.IntegerLiteralType : _ExpressibleByBuiltinIntegerLiteral> (@in τ_0_0.IntegerLiteralType, @thick τ_0_0.Type) -> @out τ_0_0 + // CHECK: apply [[TCONV]]([[ADDR]], [[LITVAR]], [[TMETA]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : ExpressibleByIntegerLiteral> (@in τ_0_0.IntegerLiteralType, @thick τ_0_0.Type) -> @out τ_0_0 x = 17 } @@ -27,7 +27,7 @@ func genericFloatingLiteral(x: T) { // CHECK: [[FLT_VAL:%.*]] = alloc_stack $T.FloatLiteralType // CHECK: apply [[BUILTIN_CONV]]([[FLT_VAL]], [[LIT_VALUE]], [[TFLT_META]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : _ExpressibleByBuiltinFloatLiteral> (Builtin.FPIEEE{{64|80}}, @thick τ_0_0.Type) -> @out τ_0_0 // CHECK: [[TVAL:%.*]] = alloc_stack $T - // CHECK: apply [[CONV]]([[TVAL]], [[FLT_VAL]], [[TMETA]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : ExpressibleByFloatLiteral, τ_0_0.FloatLiteralType : _ExpressibleByBuiltinFloatLiteral> (@in τ_0_0.FloatLiteralType, @thick τ_0_0.Type) -> @out τ_0_0 + // CHECK: apply [[CONV]]([[TVAL]], [[FLT_VAL]], [[TMETA]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : ExpressibleByFloatLiteral> (@in τ_0_0.FloatLiteralType, @thick τ_0_0.Type) -> @out τ_0_0 x = 2.5 } diff --git a/test/SILGen/interface_type_mangling.swift b/test/SILGen/interface_type_mangling.swift index e32224cfb0b89..08d438b7858bb 100644 --- a/test/SILGen/interface_type_mangling.swift +++ b/test/SILGen/interface_type_mangling.swift @@ -42,58 +42,55 @@ func g3(_ x: T, y: U) {} func h1(_ x: T) {} // CHECK: interface_type_mangling.h2 [[H_SIGNATURE]] func h2(_ x: T) {} -// FIXME: Q and AnyObject constraints should be implied by base class constraint. rdar://problem/20829810 -// FIXME: interface_type_mangling.h3 [[H_SIGNATURE]] +// CHECK: interface_type_mangling.h3 [[H_SIGNATURE]] func h3(_ x: T) {} -// FIXME: interface_type_mangling.h4 [[H_SIGNATURE]] +// CHECK: interface_type_mangling.h4 [[H_SIGNATURE]] func h4(_ x: T) {} -// FIXME: interface_type_mangling.h5 [[H_SIGNATURE]] +// CHECK: interface_type_mangling.h5 [[H_SIGNATURE]] func h5(_ x: T) {} // CHECK-LABEL: interface_type_mangling.i1 -// CHECK: [[I_SIGNATURE: \(A\) -> \(\)]] +// CHECK: [[I_SIGNATURE: \(A\) -> \(\)]] func i1(_ x: T) {} // CHECK: interface_type_mangling.i2 [[I_SIGNATURE]] func i2(_ x: T) {} -/* FIXME: ArchetypeBuilder introduces extra associated type equivalence - * classes without filtering them out as redundant. */ // CHECK-LABEL: interface_type_mangling.j01 -// CHECK: [[J_SIGNATURE: \(A\) -> \(\)]] +// CHECK: [[J_SIGNATURE: \(A\) -> \(\)]] func j01(_ x: T) {} -// FIXME: interface_type_mangling.j02 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j02 [[J_SIGNATURE]] func j02(_ x: T) {} -// FIXME: interface_type_mangling.j03 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j03 [[J_SIGNATURE]] func j03(_ x: T) {} -// FIXME: interface_type_mangling.j04 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j04 [[J_SIGNATURE]] func j04(_ x: T) {} -// FIXME: interface_type_mangling.j05 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j05 [[J_SIGNATURE]] func j05(_ x: T) {} -// FIXME: interface_type_mangling.j06 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j06 [[J_SIGNATURE]] func j06(_ x: T) {} -// FIXME: interface_type_mangling.j07 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j07 [[J_SIGNATURE]] func j07(_ x: T) {} -// FIXME: interface_type_mangling.j08 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j08 [[J_SIGNATURE]] func j08(_ x: T) {} -// FIXME: interface_type_mangling.j09 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j09 [[J_SIGNATURE]] func j09(_ x: T) {} -// FIXME: interface_type_mangling.j10 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j10 [[J_SIGNATURE]] func j10(_ x: T) {} -// FIXME: interface_type_mangling.j11 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j11 [[J_SIGNATURE]] func j11(_ x: T) {} -// FIXME: interface_type_mangling.j12 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j12 [[J_SIGNATURE]] func j12(_ x: T) {} -// FIXME: interface_type_mangling.j13 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j13 [[J_SIGNATURE]] func j13(_ x: T) {} -// FIXME: interface_type_mangling.j14 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j14 [[J_SIGNATURE]] func j14(_ x: T) {} -// FIXME: interface_type_mangling.j15 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j15 [[J_SIGNATURE]] func j15(_ x: T) {} -// FIXME: interface_type_mangling.j16 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j16 [[J_SIGNATURE]] func j16(_ x: T) {} -// FIXME: interface_type_mangling.j17 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j17 [[J_SIGNATURE]] func j17(_ x: T) {} -// FIXME: interface_type_mangling.j18 [[J_SIGNATURE]] +// CHECK: interface_type_mangling.j18 [[J_SIGNATURE]] func j18(_ x: T) {} struct S {} diff --git a/test/SILGen/specialize_attr.swift b/test/SILGen/specialize_attr.swift index cf6ace21d7065..c1708d818ec3c 100644 --- a/test/SILGen/specialize_attr.swift +++ b/test/SILGen/specialize_attr.swift @@ -34,7 +34,7 @@ public class CC { // CHECK-LABEL: sil hidden [_specialize ] @_TF15specialize_attr14specializeThisu0_rFTx1uq__T_ : $@convention(thin) (@in T, @in U) -> () { -// CHECK-LABEL: sil [noinline] [_specialize ] @_TFC15specialize_attr2CC3foouRd__S_2QQrfTqd__1gGVS_2GGx__Tqd__GS2_x__ : $@convention(method) (@in U, GG, @guaranteed CC) -> (@out U, GG) { +// CHECK-LABEL: sil [noinline] [_specialize ] @_TFC15specialize_attr2CC3foouRd__S_2QQrfTqd__1gGVS_2GGx__Tqd__GS2_x__ : $@convention(method) (@in U, GG, @guaranteed CC) -> (@out U, GG) { // ----------------------------------------------------------------------------- // Test user-specialized subscript accessors. diff --git a/test/SILGen/witness_same_type.swift b/test/SILGen/witness_same_type.swift index 99c4d1e65df10..b6ebffdd976e3 100644 --- a/test/SILGen/witness_same_type.swift +++ b/test/SILGen/witness_same_type.swift @@ -10,7 +10,7 @@ struct X {} // Ensure that the protocol witness for requirements with same-type constraints // is set correctly. -// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWV17witness_same_type3FooS_7FooableS_FS1_3foo{{.*}} : $@convention(witness_method) (@in T, @in_guaranteed Foo) -> @out X +// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWV17witness_same_type3FooS_7FooableS_FS1_3foo{{.*}} : $@convention(witness_method) (@in T, @in_guaranteed Foo) -> @out X struct Foo: Fooable { typealias Bar = X diff --git a/test/SILGen/witnesses.swift b/test/SILGen/witnesses.swift index 34f18fc08ae4e..33075c6ee05d3 100644 --- a/test/SILGen/witnesses.swift +++ b/test/SILGen/witnesses.swift @@ -428,12 +428,12 @@ struct GenericParameterNameCollision : // CHECK-LABEL: sil hidden [transparent] [thunk] @_TTW{{.*}}GenericParameterNameCollision{{.*}}GenericParameterNameCollisionProtocol{{.*}}foo{{.*}} : $@convention(witness_method) (@in T1, @in_guaranteed GenericParameterNameCollision) -> () { // CHECK: bb0(%0 : $*T1, %1 : $*GenericParameterNameCollision): - // CHECK: apply {{%.*}} + // CHECK: apply {{%.*}} func foo(_ x: U) {} // CHECK-LABEL: sil hidden [transparent] [thunk] @_TTW{{.*}}GenericParameterNameCollision{{.*}}GenericParameterNameCollisionProtocol{{.*}}bar{{.*}} : $@convention(witness_method) (@owned @callee_owned (@in T1) -> @out T.Assoc, @in_guaranteed GenericParameterNameCollision) -> () { // CHECK: bb0(%0 : $@callee_owned (@in T1) -> @out T.Assoc, %1 : $*GenericParameterNameCollision): - // CHECK: apply {{%.*}} + // CHECK: apply {{%.*}} func bar(_ x: (V) -> T.Assoc) {} } @@ -483,3 +483,26 @@ class PropertyRequirementWitnessFromBase : PropertyRequirementBase, PropertyRequ // CHECK-NEXT: strong_release // CHECK-NEXT: return [[RES]] } + +protocol Crashable { + func crash() +} + +class CrashableBase { + func crash() {} +} + +// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWurGC9witnesses16GenericCrashablex_S_9CrashableS_FS1_5crashfT_T_ : $@convention(witness_method) (@in_guaranteed GenericCrashable) -> () +// CHECK: bb0(%0 : $*GenericCrashable): +// CHECK-NEXT: [[BOX:%.*]] = alloc_stack $GenericCrashable +// CHECK-NEXT: copy_addr %0 to [initialization] [[BOX]] : $*GenericCrashable +// CHECK-NEXT: [[SELF:%.*]] = load [[BOX]] : $*GenericCrashable +// CHECK-NEXT: [[BASE:%.*]] = upcast [[SELF]] : $GenericCrashable to $CrashableBase +// CHECK-NEXT: [[FN:%.*]] = class_method [[BASE]] : $CrashableBase, #CrashableBase.crash!1 : (CrashableBase) -> () -> () , $@convention(method) (@guaranteed CrashableBase) -> () +// CHECK-NEXT: apply [[FN]]([[BASE]]) : $@convention(method) (@guaranteed CrashableBase) -> () +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: strong_release [[SELF]] : $GenericCrashable +// CHECK-NEXT: dealloc_stack [[BOX]] : $*GenericCrashable +// CHECK-NEXT: return [[RESULT]] : $() + +class GenericCrashable : CrashableBase, Crashable {} diff --git a/test/SILOptimizer/Inputs/specialize_inherited_multifile.swift b/test/SILOptimizer/Inputs/specialize_inherited_multifile.swift new file mode 100644 index 0000000000000..67a64905e39c4 --- /dev/null +++ b/test/SILOptimizer/Inputs/specialize_inherited_multifile.swift @@ -0,0 +1,14 @@ +public protocol Base {} +public protocol Derived : Base {} + +public protocol HasAssocType { + associatedtype T : Derived + + var value: T { get } +} + +public class ConcreteDerived : Derived {} + +public class ConcreteHasAssocType : HasAssocType { + public var value: ConcreteDerived { fatalError() } +} diff --git a/test/SILOptimizer/devirt_static_witness_method.sil b/test/SILOptimizer/devirt_static_witness_method.sil index 091fa72e62791..26ea408649211 100644 --- a/test/SILOptimizer/devirt_static_witness_method.sil +++ b/test/SILOptimizer/devirt_static_witness_method.sil @@ -18,7 +18,7 @@ struct S : CanAdd { func +(lhs: S, rhs: S) -> S -sil hidden [transparent] [thunk] @operator_plus_static_non_generic_witness_for_S : $@convention(thin) (@in S, @in S, @thick S.Type) -> @out S { +sil hidden [transparent] [thunk] @operator_plus_static_non_generic_witness_for_S : $@convention(thin) (@in S, @in S, @thick S.Type) -> @out S { bb0(%0 : $*S, %1 : $*S, %2 : $*S, %3 : $@thick S.Type) : %17 = tuple () return %17 : $() diff --git a/test/SILOptimizer/eager_specialize.sil b/test/SILOptimizer/eager_specialize.sil index 8c8d4fcc5d326..fbc18710055ea 100644 --- a/test/SILOptimizer/eager_specialize.sil +++ b/test/SILOptimizer/eager_specialize.sil @@ -203,7 +203,7 @@ bb2: // Preds: bb0 // Generic with specialized dispatch. No more [specialize] attribute. // -// CHECK-LABEL: sil @_TF16eager_specialize9divideNumuRxs13SignedIntegerrFzTx3denx_x : $@convention(thin) (@in T, @in T) -> (@out T, @error Error) { +// CHECK-LABEL: sil @_TF16eager_specialize9divideNumuRxs13SignedIntegerrFzTx3denx_x : $@convention(thin) (@in T, @in T) -> (@out T, @error Error) { // CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T): // CHECK: %3 = metatype $@thick T.Type // CHECK: %4 = metatype $@thick Int.Type diff --git a/test/SILOptimizer/specialize_inherited_multifile.swift b/test/SILOptimizer/specialize_inherited_multifile.swift new file mode 100644 index 0000000000000..b4732fc601e80 --- /dev/null +++ b/test/SILOptimizer/specialize_inherited_multifile.swift @@ -0,0 +1,18 @@ +// RUN: %target-swift-frontend -primary-file %s %S/Inputs/specialize_inherited_multifile.swift -O -emit-sil -sil-verify-all | %FileCheck %s + +@_semantics("optimize.sil.never") func takesBase(t: T) {} + +@inline(never) func takesHasAssocType(t: T) { + takesBase(t: t.value) +} + +// Make sure the ConcreteDerived : Base conformance is available here. + +// CHECK-LABEL: sil shared [noinline] @_TTSg5C30specialize_inherited_multifile20ConcreteHasAssocTypeS0_S_12HasAssocTypeS____TF30specialize_inherited_multifile17takesHasAssocTypeuRxS_12HasAssocTyperFT1tx_T_ : $@convention(thin) (@owned ConcreteHasAssocType) -> () +// CHECK: [[FN:%.*]] = function_ref @_TF30specialize_inherited_multifile9takesBaseuRxS_4BaserFT1tx_T_ +// CHECK: apply [[FN]]({{%.*}}) +// CHECK: return + +public func takesConcreteHasAssocType(c: ConcreteHasAssocType) { + takesHasAssocType(t: c) +} diff --git a/test/SILOptimizer/specialize_reabstraction.sil b/test/SILOptimizer/specialize_reabstraction.sil index 1b6f4a94b84b5..194830a0ec6e1 100644 --- a/test/SILOptimizer/specialize_reabstraction.sil +++ b/test/SILOptimizer/specialize_reabstraction.sil @@ -47,7 +47,7 @@ bb0(%0 : $Ref, %1 : $*Self): sil @merge_curried : $@convention(thin) (@in Self) -> @owned @callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)> { bb0(%0 : $*Self): %1 = function_ref @merge : $@convention(method) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@owned Ref<τ_1_0>, @in_guaranteed τ_0_0) -> @owned Ref<(τ_0_0.T, τ_1_0)> - %2 = partial_apply %1(%0) : $@convention(method) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@owned Ref<τ_1_0>, @in_guaranteed τ_0_0) -> @owned Ref<(τ_0_0.T, τ_1_0)> + %2 = partial_apply %1(%0) : $@convention(method) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@owned Ref<τ_1_0>, @in_guaranteed τ_0_0) -> @owned Ref<(τ_0_0.T, τ_1_0)> return %2 : $@callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)> } @@ -69,11 +69,11 @@ bb0(%0 : $Val, %1 : $Val): // CHECK: [[MERGE:%.*]] = function_ref @_TTSg5GC4main3RefSb_GS0_Sb_S_8RefProtoS__Si__merge_curried %3 = function_ref @merge_curried : $@convention(thin) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@in τ_0_0) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> // CHECK: [[PARTIAL:%.*]] = partial_apply [[MERGE]]() - %4 = partial_apply %3, Bool, Int>() : $@convention(thin) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@in τ_0_0) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> + %4 = partial_apply %3, Int, Bool>() : $@convention(thin) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@in τ_0_0) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> // CHECK-NOT: function_ref @reabstract %5 = function_ref @reabstract : $@convention(thin) <τ_0_0 where τ_0_0 : ValProto><τ_1_0> (@owned Ref<τ_0_0.T>, @owned @callee_owned (@in Ref<τ_0_0.T>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> // CHECK-NOT: partial_apply - %6 = partial_apply %5, Bool, Int>(%4) : $@convention(thin) <τ_0_0 where τ_0_0 : ValProto><τ_1_0> (@owned Ref<τ_0_0.T>, @owned @callee_owned (@in Ref<τ_0_0.T>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> + %6 = partial_apply %5, Int, Bool>(%4) : $@convention(thin) <τ_0_0 where τ_0_0 : ValProto><τ_1_0> (@owned Ref<τ_0_0.T>, @owned @callee_owned (@in Ref<τ_0_0.T>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> // CHECK: apply [[COERCE]]([[PARTIAL]]) %7 = apply %2(%6) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2> (@owned @callee_owned (@owned Ref<τ_0_0>) -> @owned @callee_owned (@owned Ref<τ_0_1>) -> @owned Ref<τ_0_2>) -> @owned @callee_owned (Val<τ_0_1>) -> Val<τ_0_2> %8 = apply %7(%1) : $@callee_owned (Val) -> Val<(Bool, Int)> diff --git a/test/Serialization/function.swift b/test/Serialization/function.swift index b7e05a3f58315..a7e93309a8743 100644 --- a/test/Serialization/function.swift +++ b/test/Serialization/function.swift @@ -81,7 +81,7 @@ struct IntWrapper2 : Wrapped { func getValue() -> Int { return 2 } } -// SIL: [[DIFFERENT_WRAPPED:%.+]] = function_ref @_TF8def_func16differentWrapped{{.*}} : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Wrapped, τ_0_1 : Wrapped, τ_0_0.Value : Equatable, τ_0_0.Value == τ_0_1.Value> (@in τ_0_0, @in τ_0_1) -> Bool +// SIL: [[DIFFERENT_WRAPPED:%.+]] = function_ref @_TF8def_func16differentWrapped{{.*}} : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Wrapped, τ_0_1 : Wrapped, τ_0_0.Value == τ_0_1.Value> (@in τ_0_0, @in τ_0_1) -> Bool _ = differentWrapped(a: IntWrapper1(), b: IntWrapper2()) diff --git a/test/Serialization/serialize_attr.swift b/test/Serialization/serialize_attr.swift index fde61b9218e51..85a82022e4fbf 100644 --- a/test/Serialization/serialize_attr.swift +++ b/test/Serialization/serialize_attr.swift @@ -54,4 +54,4 @@ class CC { // CHECK-DAG: sil hidden [fragile] [_specialize ] @_TF14serialize_attr14specializeThisu0_rFTx1uq__T_ : $@convention(thin) (@in T, @in U) -> () { -// CHECK-DAG: sil hidden [fragile] [noinline] [_specialize ] @_TFC14serialize_attr2CC3foouRd__S_2QQrfTqd__1gGVS_2GGx__Tqd__GS2_x__ : $@convention(method) (@in U, GG, @guaranteed CC) -> (@out U, GG) { +// CHECK-DAG: sil hidden [fragile] [noinline] [_specialize ] @_TFC14serialize_attr2CC3foouRd__S_2QQrfTqd__1gGVS_2GGx__Tqd__GS2_x__ : $@convention(method) (@in U, GG, @guaranteed CC) -> (@out U, GG) { diff --git a/test/decl/protocol/conforms/associated_type.swift b/test/decl/protocol/conforms/associated_type.swift index c31e30bac957b..f7bbdd9d0ae9e 100644 --- a/test/decl/protocol/conforms/associated_type.swift +++ b/test/decl/protocol/conforms/associated_type.swift @@ -2,10 +2,10 @@ class C { } -protocol P { // expected-note{{requirement specified as 'Self.AssocP' : 'C' [with Self = X]}} - associatedtype AssocP : C +protocol P { + associatedtype AssocP : C // expected-note{{protocol requires nested type 'AssocP'; do you want to add it?}} } -struct X : P { // expected-error{{'P' requires that 'X.AssocP' (aka 'Int') inherit from 'C'}} - typealias AssocP = Int +struct X : P { // expected-error{{type 'X' does not conform to protocol 'P'}} + typealias AssocP = Int // expected-note{{possibly intended match 'X.AssocP' (aka 'Int') does not inherit from 'C'}} } diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift index 9b8bf89611197..d083dc14d9828 100644 --- a/test/decl/protocol/req/recursion.swift +++ b/test/decl/protocol/req/recursion.swift @@ -23,7 +23,7 @@ public protocol P { public struct S where A.T == S {} // expected-error{{type may not reference itself as a requirement}} protocol I { - init() + init() // expected-note{{protocol requires initializer 'init()' with type '()'}} } protocol PI { diff --git a/validation-test/IDE/crashers/073-swift-archetypebuilder-enumeraterequirements.swift b/validation-test/IDE/crashers/073-swift-archetypebuilder-enumeraterequirements.swift deleted file mode 100644 index 2639b76c6efd5..0000000000000 --- a/validation-test/IDE/crashers/073-swift-archetypebuilder-enumeraterequirements.swift +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s -// REQUIRES: asserts -extension{protocol A{case={class A#^A^# \ No newline at end of file diff --git a/validation-test/IDE/crashers_fixed/073-swift-archetypebuilder-enumeraterequirements.swift b/validation-test/IDE/crashers_fixed/073-swift-archetypebuilder-enumeraterequirements.swift new file mode 100644 index 0000000000000..2207ff6a63d59 --- /dev/null +++ b/validation-test/IDE/crashers_fixed/073-swift-archetypebuilder-enumeraterequirements.swift @@ -0,0 +1,2 @@ +// RUN: %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s +extension{protocol A{case={class A#^A^# diff --git a/validation-test/compiler_crashers/28320-swift-archetypebuilder-enumeraterequirements.swift b/validation-test/compiler_crashers_fixed/28320-swift-archetypebuilder-enumeraterequirements.swift similarity index 88% rename from validation-test/compiler_crashers/28320-swift-archetypebuilder-enumeraterequirements.swift rename to validation-test/compiler_crashers_fixed/28320-swift-archetypebuilder-enumeraterequirements.swift index 8bcd10060303d..0ff558bc00383 100644 --- a/validation-test/compiler_crashers/28320-swift-archetypebuilder-enumeraterequirements.swift +++ b/validation-test/compiler_crashers_fixed/28320-swift-archetypebuilder-enumeraterequirements.swift @@ -5,6 +5,6 @@ // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -parse +// RUN: not %target-swift-frontend %s -parse // REQUIRES: asserts extension{protocol c{struct c{let e={enum T{case diff --git a/validation-test/compiler_crashers/28342-getpointerelementtype-is-not-storagetype.swift b/validation-test/compiler_crashers_fixed/28342-getpointerelementtype-is-not-storagetype.swift similarity index 91% rename from validation-test/compiler_crashers/28342-getpointerelementtype-is-not-storagetype.swift rename to validation-test/compiler_crashers_fixed/28342-getpointerelementtype-is-not-storagetype.swift index ad1476e698484..55542ba7546ba 100644 --- a/validation-test/compiler_crashers/28342-getpointerelementtype-is-not-storagetype.swift +++ b/validation-test/compiler_crashers_fixed/28342-getpointerelementtype-is-not-storagetype.swift @@ -5,7 +5,7 @@ // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: %target-swift-frontend %s -emit-ir // REQUIRES: asserts protocol A { associatedtype B diff --git a/validation-test/compiler_crashers/28383-swift-constraints-constraintgraphnode-getmembertype.swift b/validation-test/compiler_crashers_fixed/28383-swift-constraints-constraintgraphnode-getmembertype.swift similarity index 89% rename from validation-test/compiler_crashers/28383-swift-constraints-constraintgraphnode-getmembertype.swift rename to validation-test/compiler_crashers_fixed/28383-swift-constraints-constraintgraphnode-getmembertype.swift index 901ce6a4ef2cb..9648757ad8073 100644 --- a/validation-test/compiler_crashers/28383-swift-constraints-constraintgraphnode-getmembertype.swift +++ b/validation-test/compiler_crashers_fixed/28383-swift-constraints-constraintgraphnode-getmembertype.swift @@ -5,7 +5,7 @@ // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -parse +// RUN: not %target-swift-frontend %s -parse protocol A{associatedtype f:A typealias e:a protocol a diff --git a/validation-test/compiler_crashers/28398-swift-archetypebuilder-getgenericsignature.swift b/validation-test/compiler_crashers_fixed/28398-swift-archetypebuilder-getgenericsignature.swift similarity index 88% rename from validation-test/compiler_crashers/28398-swift-archetypebuilder-getgenericsignature.swift rename to validation-test/compiler_crashers_fixed/28398-swift-archetypebuilder-getgenericsignature.swift index 9c1d2033d5124..5dfb8cf453652 100644 --- a/validation-test/compiler_crashers/28398-swift-archetypebuilder-getgenericsignature.swift +++ b/validation-test/compiler_crashers_fixed/28398-swift-archetypebuilder-getgenericsignature.swift @@ -5,6 +5,6 @@ // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -parse +// RUN: not %target-swift-frontend %s -parse // REQUIRES: asserts protocol A{class A{var _=c<}protocol A{extension{func<:a diff --git a/validation-test/compiler_crashers/28399-getpointerelementtype-is-not-storagetype.swift b/validation-test/compiler_crashers_fixed/28399-getpointerelementtype-is-not-storagetype.swift similarity index 87% rename from validation-test/compiler_crashers/28399-getpointerelementtype-is-not-storagetype.swift rename to validation-test/compiler_crashers_fixed/28399-getpointerelementtype-is-not-storagetype.swift index 089f11d259b77..df8003232714a 100644 --- a/validation-test/compiler_crashers/28399-getpointerelementtype-is-not-storagetype.swift +++ b/validation-test/compiler_crashers_fixed/28399-getpointerelementtype-is-not-storagetype.swift @@ -5,8 +5,7 @@ // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -emit-ir -// REQUIRES: asserts +// RUN: %target-swift-frontend %s -emit-ir protocol A{associatedtype B } struct C{ diff --git a/validation-test/compiler_crashers/28403-swift-genericsignature-getsubstitutionmap.swift b/validation-test/compiler_crashers_fixed/28403-swift-genericsignature-getsubstitutionmap.swift similarity index 89% rename from validation-test/compiler_crashers/28403-swift-genericsignature-getsubstitutionmap.swift rename to validation-test/compiler_crashers_fixed/28403-swift-genericsignature-getsubstitutionmap.swift index fe72c425e5fa2..8c3759e4948ac 100644 --- a/validation-test/compiler_crashers/28403-swift-genericsignature-getsubstitutionmap.swift +++ b/validation-test/compiler_crashers_fixed/28403-swift-genericsignature-getsubstitutionmap.swift @@ -5,7 +5,7 @@ // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -parse +// RUN: not %target-swift-frontend %s -parse // REQUIRES: asserts { extension{ diff --git a/validation-test/stdlib/CollectionDiagnostics.swift b/validation-test/stdlib/CollectionDiagnostics.swift index 7bf4cd9df1f29..b2aa38b9a6119 100644 --- a/validation-test/stdlib/CollectionDiagnostics.swift +++ b/validation-test/stdlib/CollectionDiagnostics.swift @@ -65,8 +65,9 @@ struct GoodIndexable : Indexable { } -// expected-warning@+2 {{'Indexable' is deprecated: it will be removed in Swift 4.0. Please use 'Collection' instead}} -// expected-error@+1 {{type 'BadIndexable1' does not conform to protocol '_IndexableBase'}} +// expected-warning@+3 {{'Indexable' is deprecated: it will be removed in Swift 4.0. Please use 'Collection' instead}} +// expected-error@+2 {{type 'BadIndexable1' does not conform to protocol '_IndexableBase'}} +// expected-error@+1 {{type 'BadIndexable1' does not conform to protocol '_Indexable'}} struct BadIndexable1 : Indexable { func index(after i: Int) -> Int { return i + 1 } var startIndex: Int { return 0 }