diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index d0cada617afcc..2b5261583409b 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -145,13 +145,15 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance { /// Retrieve the type witness for the given associated type. Type getTypeWitness(AssociatedTypeDecl *assocType, - LazyResolver *resolver) const; + LazyResolver *resolver, + SubstOptions options = None) const; /// Retrieve the type witness and type decl (if one exists) /// for the given associated type. std::pair getTypeWitnessAndDecl(AssociatedTypeDecl *assocType, - LazyResolver *resolver) const; + LazyResolver *resolver, + SubstOptions options = None) const; /// Apply the given function object to each type witness within this /// protocol conformance. @@ -399,7 +401,8 @@ class NormalProtocolConformance : public ProtocolConformance, /// for the given associated type. std::pair getTypeWitnessAndDecl(AssociatedTypeDecl *assocType, - LazyResolver *resolver) const; + LazyResolver *resolver, + SubstOptions options = None) const; /// Determine whether the protocol conformance has a type witness for the /// given associated type. @@ -568,7 +571,8 @@ class SpecializedProtocolConformance : public ProtocolConformance, /// for the given associated type. std::pair getTypeWitnessAndDecl(AssociatedTypeDecl *assocType, - LazyResolver *resolver) const; + LazyResolver *resolver, + SubstOptions options = None) const; /// Given that the requirement signature of the protocol directly states /// that the given dependent type must conform to the given protocol, @@ -662,8 +666,10 @@ class InheritedProtocolConformance : public ProtocolConformance, /// for the given associated type. std::pair getTypeWitnessAndDecl(AssociatedTypeDecl *assocType, - LazyResolver *resolver) const { - return InheritedConformance->getTypeWitnessAndDecl(assocType, resolver); + LazyResolver *resolver, + SubstOptions options = None) const { + return InheritedConformance->getTypeWitnessAndDecl(assocType, resolver, + options); } /// Given that the requirement signature of the protocol directly states diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h index 8b84d2ff6e399..f64f04c6c2cd2 100644 --- a/include/swift/AST/Type.h +++ b/include/swift/AST/Type.h @@ -165,7 +165,26 @@ enum class SubstFlags { }; /// Options for performing substitutions into a type. -typedef OptionSet SubstOptions; +struct SubstOptions : public OptionSet { + typedef std::function + GetTentativeTypeWitness; + + /// Function that retrieves a tentative type witness for a protocol + /// conformance with the state \c CheckingTypeWitnesses. + GetTentativeTypeWitness getTentativeTypeWitness; + + SubstOptions(llvm::NoneType) : OptionSet(None) { } + + SubstOptions(SubstFlags flags) : OptionSet(flags) { } + + SubstOptions(OptionSet options) : OptionSet(options) { } + + SubstOptions(OptionSet options, + GetTentativeTypeWitness getTentativeTypeWitness) + : OptionSet(options), + getTentativeTypeWitness(std::move(getTentativeTypeWitness)) { } +}; inline SubstOptions operator|(SubstFlags lhs, SubstFlags rhs) { return SubstOptions(lhs) | rhs; diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 03bbe0a08382c..4dd8d70a1978c 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -215,13 +215,16 @@ ProtocolConformance::hasTypeWitness(AssociatedTypeDecl *assocType, std::pair ProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType, - LazyResolver *resolver) const { - CONFORMANCE_SUBCLASS_DISPATCH(getTypeWitnessAndDecl, (assocType, resolver)) + LazyResolver *resolver, + SubstOptions options) const { + CONFORMANCE_SUBCLASS_DISPATCH(getTypeWitnessAndDecl, + (assocType, resolver, options)) } Type ProtocolConformance::getTypeWitness(AssociatedTypeDecl *assocType, - LazyResolver *resolver) const { - return getTypeWitnessAndDecl(assocType, resolver).first; + LazyResolver *resolver, + SubstOptions options) const { + return getTypeWitnessAndDecl(assocType, resolver, options).first; } ValueDecl *ProtocolConformance::getWitnessDecl(ValueDecl *requirement, @@ -472,22 +475,39 @@ static bool resolveKnownTypeWitness(NormalProtocolConformance *conformance, std::pair NormalProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType, - LazyResolver *resolver) const { + LazyResolver *resolver, + SubstOptions options) const { if (Resolver) resolveLazyInfo(); + // Check whether we already have a type witness. auto known = TypeWitnesses.find(assocType); - if (known == TypeWitnesses.end()) { - PrettyStackTraceRequirement trace("resolving", this, assocType); - if (!resolveKnownTypeWitness(const_cast(this), - assocType)) { - assert(resolver && "Unable to resolve type witness"); - resolver->resolveTypeWitness(this, assocType); + if (known != TypeWitnesses.end()) + return known->second; + + // If this conformance is in a state where it is inferring type witnesses, + // check tentative witnesses. + if (getState() == ProtocolConformanceState::CheckingTypeWitnesses) { + // If there is a tentative-type-witness function, use it. + if (options.getTentativeTypeWitness) { + if (Type witnessType = options.getTentativeTypeWitness(this, assocType)) + return { witnessType, nullptr }; } - known = TypeWitnesses.find(assocType); - assert(known != TypeWitnesses.end() && "Didn't resolve witness?"); + + // Otherwise, we fail; this is the only case in which we can retturn a + // null type. + return { Type(), nullptr }; } + // Otherwise, resolve the type witness. + PrettyStackTraceRequirement trace("resolving", this, assocType); + if (!resolveKnownTypeWitness(const_cast(this), + assocType)) { + assert(resolver && "Unable to resolve type witness"); + resolver->resolveTypeWitness(this, assocType); + } + known = TypeWitnesses.find(assocType); + assert(known != TypeWitnesses.end() && "Didn't resolve witness?"); return known->second; } @@ -656,7 +676,8 @@ bool SpecializedProtocolConformance::hasTypeWitness( std::pair SpecializedProtocolConformance::getTypeWitnessAndDecl( AssociatedTypeDecl *assocType, - LazyResolver *resolver) const { + LazyResolver *resolver, + SubstOptions options) const { // If we've already created this type witness, return it. auto known = TypeWitnesses.find(assocType); if (known != TypeWitnesses.end()) { @@ -669,26 +690,41 @@ SpecializedProtocolConformance::getTypeWitnessAndDecl( auto substitutionMap = genericSig->getSubstitutionMap(GenericSubstitutions); + // Local function to determine whether we will end up + auto normal = GenericConformance->getRootNormalConformance(); + auto isTentativeWitness = [&] { + if (normal->getState() != ProtocolConformanceState::CheckingTypeWitnesses) + return false; + + return !normal->hasTypeWitness(assocType, nullptr); + }; + auto genericWitnessAndDecl - = GenericConformance->getTypeWitnessAndDecl(assocType, resolver); + = GenericConformance->getTypeWitnessAndDecl(assocType, resolver, options); + + auto genericWitness = genericWitnessAndDecl.first; + if (!genericWitness) + return { Type(), nullptr }; - auto &genericWitness = genericWitnessAndDecl.first; auto *typeDecl = genericWitnessAndDecl.second; // Apply the substitution we computed above auto specializedType - = genericWitness.subst(substitutionMap); - if (!specializedType) - specializedType = ErrorType::get(genericWitness); + = genericWitness.subst(substitutionMap, options); + if (!specializedType) { + if (isTentativeWitness()) + return { Type(), nullptr }; - // If the type witness was unchanged, just copy it directly. - if (specializedType.getPointer() == genericWitness.getPointer()) { - TypeWitnesses[assocType] = genericWitnessAndDecl; - return TypeWitnesses[assocType]; + specializedType = ErrorType::get(genericWitness); } - TypeWitnesses[assocType] = std::make_pair(specializedType, typeDecl); - return TypeWitnesses[assocType]; + // If we aren't in a case where we used the tentative type witness + // information, cache the result. + auto specializedWitnessAndDecl = std::make_pair(specializedType, typeDecl); + if (!isTentativeWitness() && !specializedType->hasError()) + TypeWitnesses[assocType] = specializedWitnessAndDecl; + + return specializedWitnessAndDecl; } ProtocolConformanceRef diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 068aa680fc118..20c61c401111c 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2909,17 +2909,11 @@ static Type getMemberForBaseType(LookupConformanceFn lookupConformances, if (!conformance) return failed(); if (!conformance->isConcrete()) return failed(); - // If we have an unsatisfied type witness while we're checking the - // conformances we're supposed to skip this conformance's unsatisfied type - // witnesses, and we have an unsatisfied type witness, return - // "missing". - if (conformance->getConcrete()->getRootNormalConformance()->getState() - == ProtocolConformanceState::CheckingTypeWitnesses && - !conformance->getConcrete()->hasTypeWitness(assocType, nullptr)) - return failed(); - + // Retrieve the type witness. auto witness = - conformance->getConcrete()->getTypeWitness(assocType, resolver); + conformance->getConcrete()->getTypeWitness(assocType, resolver, options); + if (!witness) + return failed(); // This is a hacky feature allowing code completion to migrate to // using Type::subst() without changing output. diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 21a9721562993..ffecc97f4f83f 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -1246,11 +1246,12 @@ RequirementCheckResult TypeChecker::checkGenericArguments( LookupConformanceFn conformances, UnsatisfiedDependency *unsatisfiedDependency, ConformanceCheckOptions conformanceOptions, - GenericRequirementsCheckListener *listener) { + GenericRequirementsCheckListener *listener, + SubstOptions options) { bool valid = true; for (const auto &rawReq : genericSig->getRequirements()) { - auto req = rawReq.subst(substitutions, conformances); + auto req = rawReq.subst(substitutions, conformances, options); if (!req) { // Another requirement will fail later; just continue. valid = false; @@ -1286,6 +1287,7 @@ RequirementCheckResult TypeChecker::checkGenericArguments( switch (status) { case RequirementCheckResult::UnsatisfiedDependency: case RequirementCheckResult::Failure: + case RequirementCheckResult::SubstitutionFailure: // pass it on up. return status; case RequirementCheckResult::Success: @@ -1308,14 +1310,16 @@ RequirementCheckResult TypeChecker::checkGenericArguments( case RequirementKind::Superclass: // Superclass requirements. if (!isSubtypeOf(firstType, secondType, dc)) { - // FIXME: Poor source-location information. - diagnose(loc, diag::type_does_not_inherit, owner, firstType, - secondType); - - diagnose(noteLoc, diag::type_does_not_inherit_requirement, rawFirstType, - rawSecondType, - genericSig->gatherGenericParamBindingsText( - {rawFirstType, rawSecondType}, substitutions)); + if (loc.isValid()) { + // FIXME: Poor source-location information. + diagnose(loc, diag::type_does_not_inherit, owner, firstType, + secondType); + + diagnose(noteLoc, diag::type_does_not_inherit_requirement, + rawFirstType, rawSecondType, + genericSig->gatherGenericParamBindingsText( + {rawFirstType, rawSecondType}, substitutions)); + } return RequirementCheckResult::Failure; } @@ -1323,13 +1327,15 @@ RequirementCheckResult TypeChecker::checkGenericArguments( case RequirementKind::SameType: if (!firstType->isEqual(secondType)) { - // FIXME: Better location info for both diagnostics. - diagnose(loc, diag::types_not_equal, owner, firstType, secondType); - - diagnose(noteLoc, diag::types_not_equal_requirement, rawFirstType, - rawSecondType, - genericSig->gatherGenericParamBindingsText( - {rawFirstType, rawSecondType}, substitutions)); + if (loc.isValid()) { + // FIXME: Better location info for both diagnostics. + diagnose(loc, diag::types_not_equal, owner, firstType, secondType); + + diagnose(noteLoc, diag::types_not_equal_requirement, rawFirstType, + rawSecondType, + genericSig->gatherGenericParamBindingsText( + {rawFirstType, rawSecondType}, substitutions)); + } return RequirementCheckResult::Failure; } @@ -1339,5 +1345,5 @@ RequirementCheckResult TypeChecker::checkGenericArguments( if (valid) return RequirementCheckResult::Success; - return RequirementCheckResult::Failure; + return RequirementCheckResult::SubstitutionFailure; } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 2debb65376d1d..1ab81a136d274 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -4012,6 +4012,7 @@ void ConformanceChecker::resolveTypeWitnesses() { typedef decltype(typeWitnesses)::ScopeTy TypeWitnessesScope; unsigned numTypeWitnesses = 0; SmallVector solutions; + SmallVector nonViableSolutions; // Information to use for diagnosing failures when we don't have // something more specific. @@ -4194,13 +4195,44 @@ void ConformanceChecker::resolveTypeWitnesses() { if (replaced.isNull()) return true; - if (checkTypeWitness(TC, DC, assocType, replaced)) - return true; - known->first = replaced; } } + // Check any same-type requirements in the protocol's requirement signature. + if (Proto->isRequirementSignatureComputed()) { + SubstOptions options(None); + options.getTentativeTypeWitness = + [&](const NormalProtocolConformance *conformance, + AssociatedTypeDecl *assocType) -> Type { + if (conformance != Conformance) return Type(0); + + return typeWitnesses.begin(assocType)->first; + }; + + auto substitutions = + SubstitutionMap::getProtocolSubstitutions( + Proto, Conformance->getType(), + ProtocolConformanceRef(Conformance)); + + auto requirementSig = Proto->getRequirementSignature(); + auto result = + TC.checkGenericArguments(DC, SourceLoc(), SourceLoc(), + Conformance->getType(), requirementSig, + QuerySubstitutionMap{substitutions}, + TypeChecker::LookUpConformance( + TC, Conformance->getDeclContext()), + nullptr, None, nullptr, options); + switch (result) { + case RequirementCheckResult::Failure: + case RequirementCheckResult::UnsatisfiedDependency: + return true; + + case RequirementCheckResult::Success: + case RequirementCheckResult::SubstitutionFailure: + return false; + } + } return false; }; @@ -4262,9 +4294,7 @@ void ConformanceChecker::resolveTypeWitnesses() { } /// Check the current set of type witnesses. - if (checkCurrentTypeWitnesses()) { - return; - } + bool invalid = checkCurrentTypeWitnesses(); // Determine whether there is already a solution with the same // bindings. @@ -4284,8 +4314,9 @@ void ConformanceChecker::resolveTypeWitnesses() { return; } - solutions.push_back(InferredTypeWitnessesSolution()); - auto &solution = solutions.back(); + auto &solutionList = invalid ? nonViableSolutions : solutions; + solutionList.push_back(InferredTypeWitnessesSolution()); + auto &solution = solutionList.back(); // Copy the type witnesses. for (auto assocType : unresolvedAssocTypes) { @@ -4479,6 +4510,12 @@ void ConformanceChecker::resolveTypeWitnesses() { } } + // If we have no solution, but we did find something that is nonviable, + // use the first nonviable one to improve error reporting. + if (solutions.empty() && !nonViableSolutions.empty()) { + solutions.push_back(std::move(nonViableSolutions.front())); + } + // If we found a single solution, take it. if (solutions.size() == 1) { // Record each of the deduced witnesses. @@ -5453,6 +5490,7 @@ bool TypeChecker::useObjectiveCBridgeableConformancesOfArgs( case RequirementCheckResult::UnsatisfiedDependency: return true; case RequirementCheckResult::Failure: + case RequirementCheckResult::SubstitutionFailure: return false; case RequirementCheckResult::Success: { bool anyUnsatisfied = false; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index a4288ee201b2a..374b280391734 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -764,6 +764,7 @@ Type TypeChecker::applyUnboundGenericArguments( case RequirementCheckResult::UnsatisfiedDependency: return Type(); case RequirementCheckResult::Failure: + case RequirementCheckResult::SubstitutionFailure: return ErrorType::get(Context); case RequirementCheckResult::Success: break; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index aa08242a42f80..01a421fbf5232 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -367,7 +367,9 @@ class GenericRequirementsCheckListener { }; /// The result of `checkGenericRequirement`. -enum class RequirementCheckResult { Success, Failure, UnsatisfiedDependency }; +enum class RequirementCheckResult { + Success, Failure, UnsatisfiedDependency, SubstitutionFailure +}; class ConformsToProtocolResult { Optional Data; @@ -1349,7 +1351,8 @@ class TypeChecker final : public LazyResolver { LookupConformanceFn conformances, UnsatisfiedDependency *unsatisfiedDependency, ConformanceCheckOptions conformanceOptions = ConformanceCheckFlags::Used, - GenericRequirementsCheckListener *listener = nullptr); + GenericRequirementsCheckListener *listener = nullptr, + SubstOptions options = None); /// Resolve the superclass of the given class. void resolveSuperclass(ClassDecl *classDecl) override; diff --git a/stdlib/public/SDK/Dispatch/Data.swift b/stdlib/public/SDK/Dispatch/Data.swift index b419d7f0f10b8..c788816e59f6c 100644 --- a/stdlib/public/SDK/Dispatch/Data.swift +++ b/stdlib/public/SDK/Dispatch/Data.swift @@ -299,6 +299,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { } public struct DispatchDataIterator : IteratorProtocol, Sequence { + public typealias Element = UInt8 /// Create an iterator over the given DispatchData public init(_data: DispatchData) { diff --git a/stdlib/public/core/Collection.swift b/stdlib/public/core/Collection.swift index 4d86d9c65d008..e72c48ac03d1f 100644 --- a/stdlib/public/core/Collection.swift +++ b/stdlib/public/core/Collection.swift @@ -88,20 +88,6 @@ public protocol _IndexableBase { /// /// - Complexity: O(1) subscript(position: Index) -> _Element { get } - - // WORKAROUND: rdar://25214066 - // FIXME(ABI)#178 (Type checker) - /// A sequence that represents a contiguous subrange of the collection's - /// elements. - associatedtype SubSequence - - /// Accesses the subsequence bounded by the given range. - /// - /// - Parameter bounds: A range of the collection's indices. The upper and - /// lower bounds of the range must be valid indices of the collection. - /// - /// - Complexity: O(1) - subscript(bounds: Range) -> SubSequence { get } /// Performs a range check in O(1), or a no-op when a range check is not /// implementable in O(1). diff --git a/stdlib/public/core/CollectionAlgorithms.swift.gyb b/stdlib/public/core/CollectionAlgorithms.swift.gyb index a9077db2c6656..795a651b621aa 100644 --- a/stdlib/public/core/CollectionAlgorithms.swift.gyb +++ b/stdlib/public/core/CollectionAlgorithms.swift.gyb @@ -475,7 +475,7 @@ ${orderingExplanation} } } -% for Self in '_Indexable', '_MutableIndexable': +% for Self in 'Collection', 'MutableCollection': %{ subscriptCommentPre = """\ @@ -511,8 +511,6 @@ subscriptCommentPost = """\ /// - Parameter bounds: A range of the collection's indices. The bounds of /// the range must be valid indices of the collection.""" }% -// FIXME(ABI)#180 (Type checker) -// WORKAROUND rdar://25214066 - should be on Collection extension ${Self} { ${subscriptCommentPre} ${subscriptCommentMid} @@ -540,8 +538,6 @@ ${subscriptCommentPost} } } -// FIXME(ABI)#180 (Type checker) -// WORKAROUND rdar://25214066 - should be on Collection extension ${Self} where Index : Strideable, Index.Stride : SignedInteger { ${subscriptCommentPre} ${subscriptCommentMid} diff --git a/stdlib/public/core/MutableCollection.swift b/stdlib/public/core/MutableCollection.swift index a1ae475bfe99a..bee79e54a0eaa 100644 --- a/stdlib/public/core/MutableCollection.swift +++ b/stdlib/public/core/MutableCollection.swift @@ -68,30 +68,6 @@ public protocol _MutableIndexable : _Indexable { /// must be a valid index of the collection that is not equal to the /// `endIndex` property. subscript(position: Index) -> _Element { get set } - - /// Accesses a contiguous subrange of the collection's elements. - /// - /// The accessed slice uses the same indices for the same elements as the - /// original collection. Always use the slice's `startIndex` property - /// instead of assuming that its indices start at a particular value. - /// - /// This example demonstrates getting a slice of an array of strings, finding - /// the index of one of the strings in the slice, and then using that index - /// in the original array. - /// - /// let streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"] - /// let streetsSlice = streets[2 ..< streets.endIndex] - /// print(streetsSlice) - /// // Prints "["Channing", "Douglas", "Evarts"]" - /// - /// let index = streetsSlice.index(of: "Evarts") // 4 - /// streets[index!] = "Eustace" - /// print(streets[index!]) - /// // Prints "Eustace" - /// - /// - Parameter bounds: A range of the collection's indices. The bounds of - /// the range must be valid indices of the collection. - subscript(bounds: Range) -> SubSequence { get set } /// Performs a range check in O(1), or a no-op when a range check is not /// implementable in O(1). diff --git a/stdlib/public/core/Range.swift.gyb b/stdlib/public/core/Range.swift.gyb index 5c732de830960..e8b6764be50b3 100644 --- a/stdlib/public/core/Range.swift.gyb +++ b/stdlib/public/core/Range.swift.gyb @@ -913,13 +913,13 @@ extension Strideable where Stride: SignedInteger { } } -extension _Indexable { +extension Collection { @_inlineable public subscript(r: R) -> SubSequence where R.Bound == Index { return self[r.relative(to: self)] } } -extension _MutableIndexable { +extension MutableCollection { @_inlineable public subscript(r: R) -> SubSequence where R.Bound == Index { get { diff --git a/stdlib/public/core/StringCharacterView.swift b/stdlib/public/core/StringCharacterView.swift index 8b78ad5402a2c..b08f882ca7c72 100644 --- a/stdlib/public/core/StringCharacterView.swift +++ b/stdlib/public/core/StringCharacterView.swift @@ -527,6 +527,8 @@ extension String.CharacterView : RangeReplaceableCollection { // Algorithms extension String.CharacterView { + public typealias SubSequence = String.CharacterView + /// Accesses the characters in the given range. /// /// The example below uses this subscript to access the characters up to, but diff --git a/test/Constraints/associated_types.swift b/test/Constraints/associated_types.swift index 6dee6f6a07a2f..fda25688dea0c 100644 --- a/test/Constraints/associated_types.swift +++ b/test/Constraints/associated_types.swift @@ -62,8 +62,8 @@ protocol XReqt {} protocol YReqt {} protocol SameTypedDefaultWithReqts { - associatedtype X: XReqt // expected-note{{}} - associatedtype Y: YReqt // expected-note{{}} + associatedtype X: XReqt + associatedtype Y: YReqt static var x: X { get } static var y: Y { get } } @@ -86,7 +86,7 @@ struct UsesSameTypedDefaultWithoutSatisfyingReqts: SameTypedDefaultWithReqts { } protocol SameTypedDefaultBaseWithReqts { - associatedtype X: XReqt // expected-note{{}} + associatedtype X: XReqt static var x: X { get } } protocol SameTypedDefaultDerivedWithReqts: SameTypedDefaultBaseWithReqts { diff --git a/test/Generics/associated_type_where_clause.swift b/test/Generics/associated_type_where_clause.swift index a94d6f079e244..5c936e15de444 100644 --- a/test/Generics/associated_type_where_clause.swift +++ b/test/Generics/associated_type_where_clause.swift @@ -157,3 +157,48 @@ protocol P4 { protocol P5: P3, P4 { associatedtype B where B == A? } + +// Associated type inference should account for where clauses. +protocol P6 { + associatedtype A +} + +struct X1 { } + +struct X2 { } + +struct Y1 : P6 { + typealias A = X1 +} + +struct Y2 : P6 { + typealias A = X2 +} + +protocol P7 { + associatedtype B: P6 // expected-note{{ambiguous inference of associated type 'B': 'Y1' vs. 'Y2'}} + associatedtype C: P6 where B.A == C.A + + func getB() -> B + func getC() -> C +} + +struct Z1 : P7 { + func getB() -> Y1 { return Y1() } + func getB() -> Y2 { return Y2() } + + func getC() -> Y1 { return Y1() } +} + +func testZ1(z1: Z1) { + let _: Z1.C = Y1() +} + + +struct Z2 : P7 { // expected-error{{type 'Z2' does not conform to protocol 'P7'}} + func getB() -> Y1 { return Y1() } // expected-note{{matching requirement 'getB()' to this declaration inferred associated type to 'Y1'}} + func getB() -> Y2 { return Y2() } // expected-note{{matching requirement 'getB()' to this declaration inferred associated type to 'Y2'}} + + func getC() -> Y1 { return Y1() } + func getC() -> Y2 { return Y2() } +} diff --git a/test/decl/protocol/conforms/failure.swift b/test/decl/protocol/conforms/failure.swift index e50db4925cb65..da58c1ecd9ad1 100644 --- a/test/decl/protocol/conforms/failure.swift +++ b/test/decl/protocol/conforms/failure.swift @@ -75,9 +75,9 @@ struct P5Conformer : P5 { // expected-error {{does not conform}} protocol P6Base { - associatedtype Foo // expected-note {{protocol requires nested type 'Foo'; do you want to add it?}} + associatedtype Foo func foo() - func bar() -> Foo + func bar() -> Foo // expected-note{{protocol requires function 'bar()' with type '() -> P6Conformer.Bar?'; do you want to add a stub?}} } extension P6Base { } @@ -85,7 +85,7 @@ protocol P6 : P6Base { associatedtype Bar // expected-note {{protocol requires nested type 'Bar'}} } extension P6 { - func bar() -> Bar? { return nil } + func bar() -> Bar? { return nil } // expected-note{{candidate has non-matching type ' () -> Self.Bar?' [with Foo = P6Conformer.Bar?]}} } struct P6Conformer : P6 { // expected-error 2 {{does not conform}} diff --git a/validation-test/compiler_crashers/28737-genericenv-nullptr-too-much-circularity.swift b/validation-test/compiler_crashers_fixed/28737-genericenv-nullptr-too-much-circularity.swift similarity index 88% rename from validation-test/compiler_crashers/28737-genericenv-nullptr-too-much-circularity.swift rename to validation-test/compiler_crashers_fixed/28737-genericenv-nullptr-too-much-circularity.swift index e5f6419f82dbd..804d8aae79c88 100644 --- a/validation-test/compiler_crashers/28737-genericenv-nullptr-too-much-circularity.swift +++ b/validation-test/compiler_crashers_fixed/28737-genericenv-nullptr-too-much-circularity.swift @@ -6,5 +6,5 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // REQUIRES: asserts -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: not %target-swift-frontend %s -emit-ir protocol A:a{typealias e}class a:A{typealias e:S diff --git a/validation-test/stdlib/CollectionType.swift.gyb b/validation-test/stdlib/CollectionType.swift.gyb index 652274227329c..ddfa51c1beecd 100644 --- a/validation-test/stdlib/CollectionType.swift.gyb +++ b/validation-test/stdlib/CollectionType.swift.gyb @@ -854,5 +854,31 @@ CollectionTypeTests.test("AssociatedTypes/${Collection}") { } % end +// rdar://problem/31830524 - associated type inference failure with +// SubSequence.SubSequence == SubSequence requirement +struct SillyIntCollection : Collection { + public var startIndex: Int { return 0 } + public var endIndex: Int { return 100 } + public subscript (position: Int) -> Int { + get { + return position + } + set { } + } + + // Note: [Int] is not the SubSequence type here. + public subscript (range: Range) -> [Int] { + get { return [] } + set { } + } + + public func index(after i: Int) -> Int {return i + 1} + public func index(before i: Int) -> Int {return i - 1} +} + +func checkSillyIntCollectionType(x: SillyIntCollection.SubSequence) { + let _: Slice = x +} + runAllTests()