diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index b3aec470b97e3..6f9895f5a9d8c 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -334,9 +334,9 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final bool isConcreteType(Type type); /// Return the concrete type that the given dependent type is constrained to, - /// or the null Type if it is not the subject of a concrete same-type - /// constraint. - Type getConcreteType(Type type); + /// the null Type if it is not the subject of a concrete same-type + /// constraint, or None if the equivalence class failed to resolve. + Optional maybeGetConcreteType(Type type); /// Return the layout constraint that the given dependent type is constrained /// to, or the null LayoutConstraint if it is not the subject of layout diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 6f3b16e9237a0..0b6333a6f97fe 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -467,13 +467,10 @@ bool GenericSignatureImpl::conformsToProtocol(Type type, ProtocolDecl *proto) { /// Determine whether the given dependent type is equal to a concrete type. bool GenericSignatureImpl::isConcreteType(Type type) { - return bool(getConcreteType(type)); + return bool(maybeGetConcreteType(type).getValueOr(Type())); } -/// Return the concrete type that the given dependent type is constrained to, -/// or the null Type if it is not the subject of a concrete same-type -/// constraint. -Type GenericSignatureImpl::getConcreteType(Type type) { +Optional GenericSignatureImpl::maybeGetConcreteType(Type type) { if (!type->isTypeParameter()) return Type(); auto &builder = *getGenericSignatureBuilder(); @@ -481,7 +478,7 @@ Type GenericSignatureImpl::getConcreteType(Type type) { builder.resolveEquivalenceClass( type, ArchetypeResolutionKind::CompleteWellFormed); - if (!equivClass) return Type(); + if (!equivClass) return None; return equivClass->concreteType; } diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index d20385dcc5ab3..ef06881d5b4fd 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -2165,6 +2165,18 @@ void EquivalenceClass::dump(llvm::raw_ostream &out, }, [&] { out << ", "; }); + if (!concreteTypeConstraints.empty()) { + out << "\nConcrete-type constraints:"; + interleave(concreteTypeConstraints, [&](const Constraint &c) { + out << "\n " << c.getSubjectDependentType({ }) + << " == " << c.value; + + if (c.source->isDerivedRequirement()) + out << " [derived]"; + }, [&] { + out << ", "; + }); + } if (concreteType) out << "\nConcrete type: " << concreteType.getString(); if (superclass) diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 682ea0cc29e1d..178fa7e378854 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -266,7 +266,8 @@ Type SubstitutionMap::lookupSubstitution(CanSubstitutableType type) const { // The generic parameter may have been made concrete by the generic signature, // substitute into the concrete type. - if (auto concreteType = genericSig->getConcreteType(genericParam)){ + if (auto concreteType = genericSig + ->maybeGetConcreteType(genericParam).getValueOr(Type())) { // Set the replacement type to an error, to block infinite recursion. replacementType = ErrorType::get(concreteType); diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index d38ab3d9f6e51..844e244025383 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -256,9 +256,9 @@ namespace { if (auto genericSig = getGenericSignature()) { if (genericSig->requiresClass(type)) { return asImpl().handleReference(type); - } else if (genericSig->isConcreteType(type)) { - return asImpl().visit(genericSig->getConcreteType(type) - ->getCanonicalType()); + } else if (auto concreteTy = genericSig + ->maybeGetConcreteType(type).getValueOr(Type())) { + return asImpl().visit(concreteTy->getCanonicalType()); } else { return asImpl().handleAddressOnly(type, RecursiveProperties::forOpaque()); @@ -281,7 +281,8 @@ namespace { auto signature = getGenericSignature(); assert(signature && "dependent type without generic signature?!"); - if (auto concreteType = signature->getConcreteType(type)) + if (auto concreteType = signature + ->maybeGetConcreteType(type).getValueOr(Type())) return concreteType->getCanonicalType(); assert(signature->requiresClass(type)); diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 3ae38ebcfc4dc..86a726d89db11 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -794,8 +794,22 @@ Type AssociatedTypeInference::computeFixedTypeWitness( auto genericSig = conformedProto->getGenericSignature(); if (!genericSig) return Type(); - Type concreteType = genericSig->getConcreteType(dependentType); - if (!concreteType) continue; + Type concreteType; + if (auto optType = genericSig->maybeGetConcreteType(dependentType)) { + if (optType.getValue()) { + concreteType = optType.getValue(); + + // If this associated type has a same-type constraint + // with Self, the fixed type is the adoptee. + } else if (genericSig->areSameTypeParameterInContext( + dependentType, proto->getSelfInterfaceType())) { + concreteType = adoptee; + } else { + continue; + } + } else { + continue; + } if (!resultType) { resultType = concreteType; @@ -936,9 +950,16 @@ Type AssociatedTypeInference::substCurrentTypeWitnesses(Type type) { llvm::DenseSet recursionCheck; foldDependentMemberTypes = [&](Type type) -> Type { if (auto depMemTy = type->getAs()) { - auto baseTy = depMemTy->getBase().transform(foldDependentMemberTypes); - if (baseTy.isNull() || baseTy->hasTypeParameter()) - return nullptr; + Type baseTy; + if (depMemTy->getBase()->is()) { + // The base type is Self. + baseTy = depMemTy->getBase(); + } else { + baseTy = depMemTy->getBase().transform(foldDependentMemberTypes); + + if (baseTy.isNull() || baseTy->hasTypeParameter()) + return nullptr; + } auto assocType = depMemTy->getAssocType(); if (!assocType) @@ -949,21 +970,26 @@ Type AssociatedTypeInference::substCurrentTypeWitnesses(Type type) { SWIFT_DEFER { recursionCheck.erase(assocType); }; - // Try to substitute into the base type. - Type result = depMemTy->substBaseType(dc->getParentModule(), baseTy); - if (!result->hasError()) - return result; - - // If that failed, check whether it's because of the conformance we're - // evaluating. - auto localConformance - = TypeChecker::conformsToProtocol( - baseTy, assocType->getProtocol(), dc, - ConformanceCheckFlags::SkipConditionalRequirements); - if (localConformance.isInvalid() || localConformance.isAbstract() || - (localConformance.getConcrete()->getRootConformance() != - conformance)) { - return nullptr; + // If the base type is Self, we are folding a fixed type witness, which + // is to say, a witness through same-type constraints on protocols; + // substituting into the base and conformance lookup are irrelevant. + if (!baseTy->is()) { + // Try to substitute into the base type. + Type result = depMemTy->substBaseType(dc->getParentModule(), baseTy); + if (!result->hasError()) + return result; + + // If that failed, check whether it's because of the conformance we're + // evaluating. + auto localConformance + = TypeChecker::conformsToProtocol( + baseTy, assocType->getProtocol(), dc, + ConformanceCheckFlags::SkipConditionalRequirements); + if (localConformance.isInvalid() || localConformance.isAbstract() || + (localConformance.getConcrete()->getRootConformance() != + conformance)) { + return nullptr; + } } // Find the tentative type witness for this associated type. @@ -974,10 +1000,13 @@ Type AssociatedTypeInference::substCurrentTypeWitnesses(Type type) { return known->first.transform(foldDependentMemberTypes); } - // The presence of a generic type parameter indicates that we - // cannot use this type binding. - if (type->is()) { - return nullptr; + if (const auto genParam = type->getAs()) { + bool isProtocolSelf = true; + if (const auto gpDecl = genParam->getDecl()) + if (adoptee->getAnyNominal() == gpDecl->getDeclContext()) + isProtocolSelf = false; + if (isProtocolSelf) + return adoptee; } return type; diff --git a/test/Generics/protocol_where_clause.swift b/test/Generics/protocol_where_clause.swift index 3fc22f935f58a..b0f904c8e6659 100644 --- a/test/Generics/protocol_where_clause.swift +++ b/test/Generics/protocol_where_clause.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -swift-version 4 +// RUN: %target-typecheck-verify-swift -swift-version 4 -print-ast %s | %FileCheck %s func needsSameType(_: T.Type, _: T.Type) {} @@ -77,3 +77,41 @@ protocol P2 { associatedtype AT } protocol P3: P2 where AT == Y {} + + +// SR-10831: +struct G {} + +protocol SR10831_P1 { + associatedtype A + associatedtype B + associatedtype C +} + +protocol SR10831_P2: SR10831_P1 where A == G> {} +protocol SR10831_P3: SR10831_P2 where B == Int, C == G {} + +struct SR10831: SR10831_P3 { // OK + // CHECK: typealias A = G?>> + // CHECK: typealias B = Int + // CHECK: typealias C = G +} + + +// SR-11671: +protocol SR11671_P1 { + associatedtype A + associatedtype B +} +protocol SR11671_P2: SR11671_P1 where A == Self {} +protocol SR11671_P3: SR11671_P2 where B == G {} + +struct SR11671_S1: SR11671_P3 { // OK + // CHECK: typealias A = SR11671_S1 + // CHECK: typealias B = G +} + +struct SR11671_S2: SR11671_P3 { // OK + // CHECK: typealias A = SR11671_S2 + // CHECK: typealias B = G?> +}