From 54918cbebb4781d3357609ad4679fd6f995d30b6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Feb 2023 11:57:59 -0500 Subject: [PATCH 1/4] AST: Remove some pointless null checks in substType() --- lib/AST/Type.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 5a08ffa8f14d0..27ff789c0b91b 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4387,9 +4387,6 @@ static Type getMemberForBaseType(LookupConformanceFn lookupConformances, return DependentMemberType::get(baseType, name); }; - // If we don't have a substituted base type, fail. - if (!substBase) return failed(); - if (auto *selfType = substBase->getAs()) substBase = selfType->getSelfType(); @@ -4690,9 +4687,6 @@ static Type substType(Type derivedType, if (auto depMemTy = dyn_cast(type)) { auto newBase = substType(depMemTy->getBase(), substitutions, lookupConformances, options); - if (!newBase) - return Type(); - return getMemberForBaseType(lookupConformances, depMemTy->getBase(), newBase, depMemTy->getAssocType(), From 2021b0c8e5412e18e82532be4dcee95712c933b4 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Feb 2023 19:16:13 -0500 Subject: [PATCH 2/4] AST: Clean up getMemberForBaseType() with an early return --- lib/AST/Type.cpp | 88 +++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 27ff789c0b91b..a6994b05715e8 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4390,6 +4390,19 @@ static Type getMemberForBaseType(LookupConformanceFn lookupConformances, if (auto *selfType = substBase->getAs()) substBase = selfType->getSelfType(); + // If the parent is a type variable or a member rooted in a type variable, + // or if the parent is a type parameter, we're done. Also handle + // UnresolvedType here, which can come up in diagnostics. + if (substBase->isTypeVariableOrMember() || + substBase->isTypeParameter() || + substBase->is()) + return getDependentMemberType(substBase); + + // All remaining cases require an associated type declaration and not just + // the name of a member type. + if (!assocType) + return failed(); + // If the parent is an archetype, extract the child archetype with the // given name. if (auto archetypeParent = substBase->getAs()) { @@ -4402,61 +4415,46 @@ static Type getMemberForBaseType(LookupConformanceFn lookupConformances, return failed(); } - // If the parent is a type variable or a member rooted in a type variable, - // or if the parent is a type parameter, we're done. Also handle - // UnresolvedType here, which can come up in diagnostics. - if (substBase->isTypeVariableOrMember() || - substBase->isTypeParameter() || - substBase->is()) - return getDependentMemberType(substBase); + auto proto = assocType->getProtocol(); + ProtocolConformanceRef conformance = + lookupConformances(origBase->getCanonicalType(), substBase, proto); - // Retrieve the member type with the given name. - - // If we know the associated type, look in the witness table. - if (assocType) { - auto proto = assocType->getProtocol(); - ProtocolConformanceRef conformance = - lookupConformances(origBase->getCanonicalType(), substBase, proto); - - if (conformance.isInvalid()) - return failed(); + if (conformance.isInvalid()) + return failed(); - Type witnessTy; + Type witnessTy; - // Retrieve the type witness. - if (conformance.isPack()) { - auto *packConformance = conformance.getPack(); + // Retrieve the type witness. + if (conformance.isPack()) { + auto *packConformance = conformance.getPack(); - witnessTy = packConformance->getAssociatedType( - assocType->getDeclaredInterfaceType()); - } else if (conformance.isConcrete()) { - auto witness = - conformance.getConcrete()->getTypeWitnessAndDecl(assocType, options); + witnessTy = packConformance->getAssociatedType( + assocType->getDeclaredInterfaceType()); + } else if (conformance.isConcrete()) { + auto witness = + conformance.getConcrete()->getTypeWitnessAndDecl(assocType, options); - witnessTy = witness.getWitnessType(); - if (!witnessTy || witnessTy->hasError()) - return failed(); + witnessTy = witness.getWitnessType(); + if (!witnessTy || witnessTy->hasError()) + return failed(); - // This is a hacky feature allowing code completion to migrate to - // using Type::subst() without changing output. - if (options & SubstFlags::DesugarMemberTypes) { - if (auto *aliasType = dyn_cast(witnessTy.getPointer())) - witnessTy = aliasType->getSinglyDesugaredType(); + // This is a hacky feature allowing code completion to migrate to + // using Type::subst() without changing output. + if (options & SubstFlags::DesugarMemberTypes) { + if (auto *aliasType = dyn_cast(witnessTy.getPointer())) + witnessTy = aliasType->getSinglyDesugaredType(); - // Another hack. If the type witness is a opaque result type. They can - // only be referred using the name of the associated type. - if (witnessTy->is()) - witnessTy = witness.getWitnessDecl()->getDeclaredInterfaceType(); - } + // Another hack. If the type witness is a opaque result type. They can + // only be referred using the name of the associated type. + if (witnessTy->is()) + witnessTy = witness.getWitnessDecl()->getDeclaredInterfaceType(); } - - if (!witnessTy || witnessTy->is()) - return failed(); - - return witnessTy; } - return failed(); + if (!witnessTy || witnessTy->is()) + return failed(); + + return witnessTy; } ProtocolConformanceRef LookUpConformanceInModule:: From 5ef5957bfc86222ead29731500900b8446df9c03 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Feb 2023 20:01:41 -0500 Subject: [PATCH 3/4] AST: ArchetypeType::getNestedType() should fail gracefully if the associated type is not a valid member type We need this because AutoDiff likes to substitute invalid type parameters. --- lib/AST/Type.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index a6994b05715e8..6923c990700fb 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3564,9 +3564,14 @@ bool ArchetypeType::requiresClass() const { Type ArchetypeType::getNestedType(AssociatedTypeDecl *assocType) { Type interfaceType = getInterfaceType(); Type memberInterfaceType = - DependentMemberType::get(interfaceType, assocType->getName()); - return getGenericEnvironment()->getOrCreateArchetypeFromInterfaceType( - memberInterfaceType); + DependentMemberType::get(interfaceType, assocType); + auto genericSig = getGenericEnvironment()->getGenericSignature(); + if (genericSig->isValidTypeParameter(memberInterfaceType)) { + return getGenericEnvironment()->getOrCreateArchetypeFromInterfaceType( + memberInterfaceType); + } + + return Type(); } Type ArchetypeType::getNestedTypeByName(Identifier name) { From 29a45d9a67803aa0f0ee7ca60ae6a131d258d21a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Feb 2023 20:02:21 -0500 Subject: [PATCH 4/4] AST: getMemberForBaseType() should use ArchetypeType::getNestedType() instead of getNestedTypeByName() --- lib/AST/Type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 6923c990700fb..865b5a639678a 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -4411,7 +4411,7 @@ static Type getMemberForBaseType(LookupConformanceFn lookupConformances, // If the parent is an archetype, extract the child archetype with the // given name. if (auto archetypeParent = substBase->getAs()) { - if (Type memberArchetypeByName = archetypeParent->getNestedTypeByName(name)) + if (Type memberArchetypeByName = archetypeParent->getNestedType(assocType)) return memberArchetypeByName; // If looking for an associated type and the archetype is constrained to a