Skip to content

[IDE] Fix another GenericFunctionType subst crasher #38503

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1116,10 +1116,22 @@ class alignas(1 << TypeAlignInBits) TypeBase {
TypeSubstitutionMap getMemberSubstitutions(const ValueDecl *member,
GenericEnvironment *genericEnv=nullptr);

/// Retrieve the type of the given property as seen through the given base
/// type, substituting generic arguments where necessary. This is the same as
/// the more general overload of \c TypeBase::getTypeOfMember, but defaults to
/// the property's interface type for the \c memberType.
///
/// \param module The module in which the substitution occurs.
///
/// \param member The property whose type we are substituting.
///
/// \returns The resulting property type.
Type getTypeOfMember(ModuleDecl *module, const VarDecl *member);

/// Retrieve the type of the given member as seen through the given base
/// type, substituting generic arguments where necessary.
///
/// This routine allows one to take a concrete type (the "this" type) and
/// This routine allows one to take a concrete type (the "self" type) and
/// and a member of that type (or one of its superclasses), then determine
/// what type an access to that member through the base type will have.
/// For example, given:
Expand All @@ -1130,20 +1142,23 @@ class alignas(1 << TypeAlignInBits) TypeBase {
/// }
/// \endcode
///
/// Given the type \c Vector<Int> and the member \c add, the resulting type
/// of the member will be \c (self : Vector<Int>) -> (value : Int) -> ().
/// Given the type \c Vector<Int>, the member \c add, and its method interface
/// type (value: T) -> Void the resulting type will be (value: Int) -> Void.
///
/// \param module The module in which the substitution occurs.
///
/// \param member The member whose type we are substituting.
///
/// \param memberType The type of the member, in which archetypes will be
/// replaced by the generic arguments provided by the base type. If null,
/// the member's type will be used.
/// \param memberType The type of the member in which generic parameters will
/// be replaced by the generic arguments provided by the base type. Note this
/// must not be a GenericFunctionType. For a method, either strip the self
/// parameter and generic signature using e.g \c getMethodInterfaceType, or
/// use \c substGenericArgs if you want to substitute types for any of the
/// method's generic parameters.
///
/// \returns the resulting member type.
/// \returns The resulting member type.
Type getTypeOfMember(ModuleDecl *module, const ValueDecl *member,
Type memberType = Type());
Type memberType);

/// Get the type of a superclass member as seen from the subclass,
/// substituting generic parameters, dynamic Self return, and the
Expand Down
3 changes: 1 addition & 2 deletions include/swift/SIL/AbstractionPattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,8 +794,7 @@ class AbstractionPattern {
/// Note that, for most purposes, you should lower a field's type against its
/// *unsubstituted* interface type.
AbstractionPattern
unsafeGetSubstFieldType(ValueDecl *member,
CanType origMemberType = CanType()) const;
unsafeGetSubstFieldType(ValueDecl *member, CanType origMemberType) const;

private:
/// Return an abstraction pattern for the curried type of an
Expand Down
14 changes: 8 additions & 6 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4312,8 +4312,16 @@ SubstitutionMap TypeBase::getMemberSubstitutionMap(
LookUpConformanceInModule(module));
}

Type TypeBase::getTypeOfMember(ModuleDecl *module, const VarDecl *member) {
return getTypeOfMember(module, member, member->getInterfaceType());
}

Type TypeBase::getTypeOfMember(ModuleDecl *module, const ValueDecl *member,
Type memberType) {
assert(memberType);
assert(!memberType->is<GenericFunctionType>() &&
"Generic function types are not supported");

if (is<ErrorType>())
return ErrorType::get(getASTContext());

Expand All @@ -4322,12 +4330,6 @@ Type TypeBase::getTypeOfMember(ModuleDecl *module, const ValueDecl *member,
return objectTy->getTypeOfMember(module, member, memberType);
}

// If no member type was provided, use the member's type.
if (!memberType)
memberType = member->getInterfaceType();

assert(memberType);

// Perform the substitution.
auto substitutions = getMemberSubstitutionMap(module, member);
return memberType.subst(substitutions);
Expand Down
16 changes: 7 additions & 9 deletions lib/IDE/ConformingMethodList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,20 @@ void ConformingMethodListCallbacks::getMatchingMethods(
/// Returns true if \p VD is a instance method whose return type conforms
/// to the requested protocols.
bool isMatchingMethod(ValueDecl *VD) {
if (!isa<FuncDecl>(VD))
auto *FD = dyn_cast<FuncDecl>(VD);
if (!FD)
return false;
if (VD->isStatic() || VD->isOperator())
if (FD->isStatic() || FD->isOperator())
return false;

auto declTy = T->getTypeOfMember(CurModule, VD);
if (declTy->is<ErrorType>())
auto resultTy = T->getTypeOfMember(CurModule, FD,
FD->getResultInterfaceType());
if (resultTy->is<ErrorType>())
return false;

// Strip '(Self.Type) ->' and parameters.
declTy = declTy->castTo<AnyFunctionType>()->getResult();
declTy = declTy->castTo<AnyFunctionType>()->getResult();

// The return type conforms to any of the requested protocols.
for (auto Proto : ExpectedTypes) {
if (CurModule->conformsToProtocol(declTy, Proto))
if (CurModule->conformsToProtocol(resultTy, Proto))
return true;
}

Expand Down
12 changes: 7 additions & 5 deletions lib/IDE/TypeContextInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,13 @@ void ContextInfoCallbacks::getImplicitMembers(
return true;

// Static properties which is convertible to 'Self'.
if (isa<VarDecl>(VD) && VD->isStatic()) {
auto declTy = T->getTypeOfMember(CurModule, VD);
if (declTy->isEqual(T) ||
swift::isConvertibleTo(declTy, T, /*openArchetypes=*/true, *DC))
return true;
if (auto *Var = dyn_cast<VarDecl>(VD)) {
if (Var->isStatic()) {
auto declTy = T->getTypeOfMember(CurModule, Var);
if (declTy->isEqual(T) ||
swift::isConvertibleTo(declTy, T, /*openArchetypes=*/true, *DC))
return true;
}
}

return false;
Expand Down
3 changes: 1 addition & 2 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -918,8 +918,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
SmallVector<llvm::Metadata *, 16> Elements;
unsigned OffsetInBits = 0;
for (VarDecl *VD : Decl->getStoredProperties()) {
auto memberTy =
BaseTy->getTypeOfMember(IGM.getSwiftModule(), VD, nullptr);
auto memberTy = BaseTy->getTypeOfMember(IGM.getSwiftModule(), VD);

if (auto DbgTy = CompletedDebugTypeInfo::getFromTypeInfo(
VD->getInterfaceType(),
Expand Down
7 changes: 3 additions & 4 deletions lib/SIL/IR/AbstractionPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1135,13 +1135,12 @@ AbstractionPattern
AbstractionPattern::unsafeGetSubstFieldType(ValueDecl *member,
CanType origMemberInterfaceType)
const {
assert(origMemberInterfaceType);
if (isTypeParameterOrOpaqueArchetype()) {
// Fall back to the generic abstraction pattern for the member.
auto sig = member->getDeclContext()->getGenericSignatureOfContext();
CanType memberTy = origMemberInterfaceType
? origMemberInterfaceType
: member->getInterfaceType()->getCanonicalType(sig);
return AbstractionPattern(sig.getCanonicalSignature(), memberTy);
return AbstractionPattern(sig.getCanonicalSignature(),
origMemberInterfaceType);
}

switch (getKind()) {
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/IR/SILType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ SILType SILType::getFieldType(VarDecl *field, TypeConverter &TC,
substFieldTy = origFieldTy.getType();
} else {
substFieldTy =
getASTType()->getTypeOfMember(&TC.M, field, nullptr)->getCanonicalType();
getASTType()->getTypeOfMember(&TC.M, field)->getCanonicalType();
}

auto loweredTy =
Expand Down
5 changes: 4 additions & 1 deletion lib/SIL/IR/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1768,7 +1768,10 @@ namespace {
// field type against the declaration's interface type as we normally
// would, we use the substituted field type in order to accurately
// preserve the properties of the aggregate.
auto origFieldType = origType.unsafeGetSubstFieldType(field);
auto sig = field->getDeclContext()->getGenericSignatureOfContext();
auto interfaceTy = field->getInterfaceType()->getCanonicalType(sig);
auto origFieldType = origType.unsafeGetSubstFieldType(field,
interfaceTy);

properties.addSubobject(classifyType(origFieldType, substFieldType,
TC, Expansion));
Expand Down
7 changes: 5 additions & 2 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -998,8 +998,11 @@ ConstraintSystem::getPropertyWrapperInformation(
if (!decl->hasAttachedPropertyWrapper())
return None;

return std::make_pair(decl,
decl->getPropertyWrapperBackingPropertyType());
auto backingTy = decl->getPropertyWrapperBackingPropertyType();
if (!backingTy)
return None;

return std::make_pair(decl, backingTy);
});
}

Expand Down
7 changes: 3 additions & 4 deletions lib/Sema/TypeCheckSwitchStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,11 +844,10 @@ namespace {

// .e(a: X, b: X) -> (a: X, b: X)
// .f((a: X, b: X)) -> ((a: X, b: X)
auto eedTy = tp->getCanonicalType()->getTypeOfMember(
E->getModuleContext(), eed,
eed->getArgumentInterfaceType());
SmallVector<Space, 4> constElemSpaces;
if (eedTy) {
if (auto payloadTy = eed->getArgumentInterfaceType()) {
auto eedTy = tp->getCanonicalType()->getTypeOfMember(
E->getModuleContext(), eed, payloadTy);
if (auto *TTy = eedTy->getAs<TupleType>()) {
Space::getTupleTypeSpaces(eedTy, TTy, constElemSpaces);
} else if (auto *TTy =
Expand Down
29 changes: 29 additions & 0 deletions test/IDE/conforming-methods-generic.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// RUN: %target-swift-ide-test -conforming-methods -source-filename %s -code-completion-token=CM1 -module-name MyModule -conforming-methods-expected-types '$s8MyModule6TargetPD' | %FileCheck %s -check-prefix=SI
// RUN: %target-swift-ide-test -conforming-methods -source-filename %s -code-completion-token=CM2 -module-name MyModule -conforming-methods-expected-types '$s8MyModule6TargetPD' | %FileCheck %s -check-prefix=SF

protocol Target {}
struct Concrete : Target {}

struct S<T> {
func returnsAnything<U>() -> U { fatalError() }
}

extension S where T == Int {
func returnsConcrete<U>(_ x: U) -> Concrete { fatalError() }
}

func test(si: S<Int>, sf: S<Float>) {
si.#^CM1^#
// SI: -----BEGIN CONFORMING METHOD LIST-----
// SI-NEXT: - TypeName: S<Int>
// SI-NEXT: - Members:
// SI-NEXT: - Name: returnsConcrete(_:)
// SI-NEXT: TypeName: Concrete
// SI-NEXT: -----END CONFORMING METHOD LIST-----

sf.#^CM2^#
// SF: -----BEGIN CONFORMING METHOD LIST-----
// SF-NEXT: - TypeName: S<Float>
// SF-NEXT: - Members: []
// SF-NEXT: -----END CONFORMING METHOD LIST-----
}
9 changes: 9 additions & 0 deletions test/IDE/conforming-methods-rdar77259607.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %target-swift-ide-test -conforming-methods -source-filename %s -code-completion-token=CC

protocol MyView {}

extension MyView {
func foo<Content>() -> Content? {
return nil#^CC^#
}
}