diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h index abb790e466a14..5481e97b01f84 100644 --- a/include/swift/AST/GenericSignatureBuilder.h +++ b/include/swift/AST/GenericSignatureBuilder.h @@ -757,7 +757,7 @@ class GenericSignatureBuilder { /// \param resolutionKind How to perform the resolution. /// /// \param wantExactPotentialArchetype Whether to return the precise - /// potential archetype described by the type (vs. just the equivalance + /// potential archetype described by the type (vs. just the equivalence /// class and resolved type). ResolvedType maybeResolveEquivalenceClass( Type type, diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 7d05c54be064f..a1126184199d6 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -6265,7 +6265,7 @@ static bool removalDisconnectsEquivalenceClass( // derived edges). if (fromComponentIndex == toComponentIndex) return false; - /// Describes the parents in the equivalance classes we're forming. + /// Describes the parents in the equivalence classes we're forming. SmallVector parents; for (unsigned i : range(equivClass->derivedSameTypeComponents.size())) { parents.push_back(i); diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 823befcbacd9c..13a2cfc39f34e 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -805,25 +805,30 @@ Type AssociatedTypeInference::computeFixedTypeWitness( AssociatedTypeDecl *assocType) { // Look at all of the inherited protocols to determine whether they // require a fixed type for this associated type. - Type dependentType = assocType->getDeclaredInterfaceType(); Type resultType; for (auto conformedProto : adoptee->getAnyNominal()->getAllProtocols()) { if (!conformedProto->inheritsFrom(assocType->getProtocol())) continue; - auto genericSig = conformedProto->getGenericSignature(); + const auto genericSig = conformedProto->getGenericSignature(); if (!genericSig) return Type(); - Type concreteType = genericSig->getConcreteType(dependentType); - if (!concreteType) continue; + const auto nestedType = genericSig->getCanonicalTypeInContext( + DependentMemberType::get(conformedProto->getSelfInterfaceType(), + assocType->getName())); + if (nestedType->isEqual(conformedProto->getSelfInterfaceType())) { + // Self is a valid fixed type witness. + } else if (nestedType->isTypeParameter()) { + continue; + } if (!resultType) { - resultType = concreteType; + resultType = nestedType; continue; } // FIXME: Bailing out on ambiguity. - if (!resultType->isEqual(concreteType)) + if (!resultType->isEqual(nestedType)) return Type(); } @@ -887,7 +892,7 @@ AssociatedTypeInference::computeAbstractTypeWitness( return AbstractTypeWitness::forFixed(assocType, concreteType); // If we can form a default type, do so. - if (auto typeWitness = computeDefaultTypeWitness(assocType)) + if (const auto &typeWitness = computeDefaultTypeWitness(assocType)) return typeWitness; // If there is a generic parameter of the named type, use that. diff --git a/test/decl/protocol/req/associated_type_inference.swift b/test/decl/protocol/req/associated_type_inference.swift index 0de5e8ec1b6bc..817f08de5e85d 100644 --- a/test/decl/protocol/req/associated_type_inference.swift +++ b/test/decl/protocol/req/associated_type_inference.swift @@ -676,21 +676,12 @@ struct S40: P40c { typealias B = Self } -// Self is not treated as a fixed type witness. +// Fails to find the fixed type witness B == FIXME_S1. protocol FIXME_P1a { - associatedtype A // expected-note {{protocol requires nested type 'A'}} -} -protocol FIXME_P1b: FIXME_P1a where A == Self {} -// expected-error@+2 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1a'}} -// expected-error@+1 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1b'}} -struct FIXME_S1: FIXME_P1b {} - -// Fails to find the fixed type witness B == FIXME_S2. -protocol FIXME_P2a { associatedtype A: Equatable = Never // expected-note {{protocol requires nested type 'A'}} - associatedtype B: FIXME_P2a // expected-note {{protocol requires nested type 'B'}} + associatedtype B: FIXME_P1a // expected-note {{protocol requires nested type 'B'}} } -protocol FIXME_P2b: FIXME_P2a where B == FIXME_S2 {} -// expected-error@+2 {{type 'FIXME_S2' does not conform to protocol 'FIXME_P2a'}} -// expected-error@+1 {{type 'FIXME_S2' does not conform to protocol 'FIXME_P2b'}} -struct FIXME_S2: FIXME_P2b {} +protocol FIXME_P1b: FIXME_P1a where B == FIXME_S1 {} +// expected-error@+2 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1a'}} +// expected-error@+1 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1b'}} +struct FIXME_S1: FIXME_P1b {} diff --git a/test/decl/protocol/req/associated_type_inference_fixed_type.swift b/test/decl/protocol/req/associated_type_inference_fixed_type.swift new file mode 100644 index 0000000000000..4b8f6c99b3289 --- /dev/null +++ b/test/decl/protocol/req/associated_type_inference_fixed_type.swift @@ -0,0 +1,105 @@ +// RUN: %target-typecheck-verify-swift + +protocol P1 where A == Never { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// FIXME: Should this infer A := Never? +struct S1: P1 {} // expected-error {{type 'S1' does not conform to protocol 'P1'}} + +protocol P2a { + associatedtype A +} +protocol P2b: P2a where A == Never {} +protocol P2c: P2b {} +struct S2a: P2b {} // OK, A := Never +struct S2b: P2c {} // OK, A := Never + +// Fixed type witnesses can reference dependent members. +protocol P3a { + associatedtype A + associatedtype B +} +protocol P3b: P3a where A == [B] {} +struct S3: P3b { // OK, A := [Never], B := Never + typealias B = Never +} + +protocol P4 {} +extension P4 { + typealias B = Self +} +struct S4: P4, P3b {} // OK, A := [S4], B := S4 + +// Self is a valid fixed type witness. +protocol P5a { + associatedtype A +} +protocol P5b: P5a where A == Self {} +struct S5: P5b {} // OK, A := S5 + + +protocol P6 where A == Never { // expected-error {{same-type constraint type 'Never' does not conform to required protocol 'P6'}} + // expected-error@+2 {{same-type constraint type 'Never' does not conform to required protocol 'P6'}} + // expected-note@+1 {{protocol requires nested type 'A}} + associatedtype A: P6 +} +struct S6: P6 {} // expected-error {{type 'S6' does not conform to protocol 'P6'}} + +protocol P7a where A == Never { + associatedtype A +} +// expected-error@+2 {{'Self.A' cannot be equal to both 'Bool' and 'Never'}} +// expected-note@+1 {{same-type constraint 'Self.A' == 'Never' implied here}} +protocol P7b: P7a where A == Bool {} +struct S7: P7b {} + +protocol P8 where A == Bool { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// expected-error@+2 {{type 'S8' does not conform to protocol 'P7a'}} +// expected-error@+1 {{type 'S8' does not conform to protocol 'P8'}} +struct S8: P8, P7a {} + +protocol P9a where A == Never { + associatedtype A +} +protocol P9b: P9a { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// FIXME: Associated type restatement sabotages the conformance. +// expected-error@+2 {{type 'S9a' does not conform to protocol 'P9a'}} +// expected-error@+1 {{type 'S9a' does not conform to protocol 'P9b'}} +struct S9a: P9b {} +// expected-error@+2 {{'P9a' requires the types 'S9b.A' (aka 'Bool') and 'Never' be equivalent}} +// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S9b]}} +struct S9b: P9b { + typealias A = Bool +} +struct S9c: P9b { // OK, S9c.A does not contradict Self.A == Never. + typealias Sugar = Never + typealias A = Sugar +} + +protocol P10 {} +extension P10 { + typealias A = Bool +} +// FIXME: 'P10 extension.A' should not be considered a viable type witness; +// instead, the compiler should infer A := Never and synthesize S10.A. +// expected-error@+2 {{'P9a' requires the types 'S10.A' (aka 'Bool') and 'Never' be equivalent}} +// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S10]}} +struct S10: P10, P9a {} + +protocol P11a { + associatedtype A +} +protocol P11b: P11a where A == Never {} +protocol Q11 { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// FIXME: Unrelated protocols with a matching associated type should +// also be considered when computing a fixed type witness. +// expected-error@+3 {{type 'S11' does not conform to protocol 'Q11'}} +// expected-error@+2 {{type 'S11' does not conform to protocol 'P11a'}} +// expected-error@+1 {{type 'S11' does not conform to protocol 'P11b'}} +struct S11: Q11, P11b {}