Skip to content
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
3 changes: 3 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
/// the given type.
Type replaceDynamicSelfType(Type newSelfType);

/// Hack to deal with ConstructorDecl interface types.
Type withCovariantResultType();

/// Deprecated in favor of the above.
Type replaceCovariantResultType(Type newResultType,
unsigned uncurryLevel);
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4076,7 +4076,7 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD,
// Methods returning 'Self' have a dynamic 'self'.
//
// FIXME: All methods of non-final classes should have this.
else if (wantDynamicSelf && FD->hasDynamicSelfResult())
else if (wantDynamicSelf && FD->getResultInterfaceType()->hasDynamicSelfType())
isDynamicSelf = true;

} else if (auto *CD = dyn_cast<ConstructorDecl>(AFD)) {
Expand Down
36 changes: 36 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,42 @@ Type TypeBase::replaceDynamicSelfType(Type newSelfType) {
});
}

Type TypeBase::withCovariantResultType() {
// Unwrap the outer function type.
auto fnType = this->castTo<AnyFunctionType>();
ASSERT(fnType->getParams().size() == 1);

// Unwrap the inner function type.
auto resultFnType = fnType->getResult()->castTo<FunctionType>();
auto resultType = resultFnType->getResult();

bool wasOptional = false;
if (auto objectType = resultType->getOptionalObjectType()) {
wasOptional = true;
resultType = objectType;
}

ASSERT(resultType->getClassOrBoundGenericClass());
resultType = DynamicSelfType::get(resultType, getASTContext());

// Rebuild the inner function type.
if (wasOptional)
resultType = OptionalType::get(resultType);

resultFnType = FunctionType::get(resultFnType->getParams(), resultType,
resultFnType->getExtInfo());

// Rebuild the outer function type.
if (auto genericFn = dyn_cast<GenericFunctionType>(fnType)) {
return GenericFunctionType::get(genericFn->getGenericSignature(),
fnType->getParams(), resultFnType,
fnType->getExtInfo());
}

return FunctionType::get(fnType->getParams(), resultFnType,
fnType->getExtInfo());
}

Type TypeBase::replaceCovariantResultType(Type newResultType,
unsigned uncurryLevel) {
if (uncurryLevel == 0) {
Expand Down
5 changes: 3 additions & 2 deletions lib/AST/TypeSubstitution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,8 +885,9 @@ Type TypeBase::adjustSuperclassMemberDeclType(const ValueDecl *baseDecl,

if (auto *afd = dyn_cast<AbstractFunctionDecl>(baseDecl)) {
type = type->replaceSelfParameterType(this);
if (isa<ConstructorDecl>(afd))
return type->replaceCovariantResultType(this, /*uncurryLevel=*/2);
if (isa<ConstructorDecl>(afd) &&
afd->getDeclContext()->getSelfClassDecl())
type = type->withCovariantResultType();
}

return type->replaceDynamicSelfType(this);
Expand Down
3 changes: 2 additions & 1 deletion lib/PrintAsClang/DeclAndTypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1250,7 +1250,8 @@ class DeclAndTypePrinter::Implementation
// Constructors and methods returning DynamicSelf return
// instancetype.
if (isa<ConstructorDecl>(AFD) ||
(isa<FuncDecl>(AFD) && cast<FuncDecl>(AFD)->hasDynamicSelfResult() &&
(isa<FuncDecl>(AFD) &&
cast<FuncDecl>(AFD)->getResultInterfaceType()->hasDynamicSelfType() &&
!AFD->hasAsync())) {
if (errorConvention && errorConvention->stripsResultOptionality()) {
printNullability(OTK_Optional, NullabilityPrintKind::ContextSensitive);
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/Verifier/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4283,7 +4283,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
// If the method returns dynamic Self, substitute AnyObject for the
// result type.
if (auto fnDecl = dyn_cast<FuncDecl>(method.getDecl())) {
if (fnDecl->hasDynamicSelfResult()) {
if (fnDecl->getResultInterfaceType()->hasDynamicSelfType()) {
auto anyObjectTy = C.getAnyObjectType();
for (auto &result : results) {
auto resultTy =
Expand Down
52 changes: 27 additions & 25 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1403,23 +1403,25 @@ namespace {
// special handling.
if (baseExpr) {
if (auto *fnDecl = dyn_cast<AbstractFunctionDecl>(declOrClosure)) {
if (fnDecl->hasDynamicSelfResult()) {
Type convTy;

if (cs.getType(baseExpr)->hasOpenedExistential()) {
// FIXME: Sometimes we need to convert to an opened existential
// first, because CovariantReturnConversionExpr does not support
// direct conversions from a class C to an existential C & P.
convTy = cs.getType(baseExpr)->getMetatypeInstanceType();
convTy =
thunkTy->getResult()->replaceCovariantResultType(convTy, 0);
} else {
convTy = thunkTy->getResult();
}
if (fnDecl->getDeclContext()->getSelfClassDecl()) {
if (fnDecl->hasDynamicSelfResult()) {
Type convTy;

if (cs.getType(baseExpr)->hasOpenedExistential()) {
// FIXME: Sometimes we need to convert to an opened existential
// first, because CovariantReturnConversionExpr does not support
// direct conversions from a class C to an existential C & P.
convTy = cs.getType(baseExpr)->getMetatypeInstanceType();
if (thunkTy->getResult()->getOptionalObjectType())
convTy = OptionalType::get(thunkTy);
} else {
convTy = thunkTy->getResult();
}

if (!thunkBody->getType()->isEqual(convTy)) {
thunkBody = cs.cacheType(
new (ctx) CovariantReturnConversionExpr(thunkBody, convTy));
if (!thunkBody->getType()->isEqual(convTy)) {
thunkBody = cs.cacheType(
new (ctx) CovariantReturnConversionExpr(thunkBody, convTy));
}
}
}
}
Expand Down Expand Up @@ -1964,9 +1966,10 @@ namespace {

auto *func = dyn_cast<FuncDecl>(member);
if (func && func->getResultInterfaceType()->hasDynamicSelfType()) {
refTy = refTy->replaceCovariantResultType(containerTy, 2);
adjustedRefTy = adjustedRefTy->replaceCovariantResultType(
containerTy, 2);
ASSERT(refTy->hasDynamicSelfType());
refTy = refTy->replaceDynamicSelfType(containerTy);
adjustedRefTy = adjustedRefTy->replaceDynamicSelfType(
containerTy);
}

// Handle all other references.
Expand Down Expand Up @@ -2110,10 +2113,9 @@ namespace {
//
// Note: For unbound references this is handled inside the thunk.
if (!isUnboundInstanceMember &&
!member->getDeclContext()->getSelfProtocolDecl()) {
member->getDeclContext()->getSelfClassDecl()) {
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
if (func->hasDynamicSelfResult() &&
!baseTy->getOptionalObjectType()) {
if (func->hasDynamicSelfResult()) {
// FIXME: Once CovariantReturnConversionExpr (unchecked_ref_cast)
// supports a class existential dest., consider using the opened
// type directly to avoid recomputing the 'Self' replacement and
Expand Down Expand Up @@ -2543,9 +2545,9 @@ namespace {
new (ctx) OtherConstructorDeclRefExpr(ref, loc, implicit, resultTy));

// Wrap in covariant `Self` return if needed.
if (selfTy->hasReferenceSemantics()) {
auto covariantTy = resultTy->replaceCovariantResultType(
cs.getType(base)->getWithoutSpecifierType(), 2);
if (ref.getDecl()->getDeclContext()->getSelfClassDecl()) {
auto covariantTy = resultTy->withCovariantResultType()
->replaceDynamicSelfType(cs.getType(base)->getWithoutSpecifierType());
if (!covariantTy->isEqual(resultTy))
ctorRef = cs.cacheType(
new (ctx) CovariantFunctionConversionExpr(ctorRef, covariantTy));
Expand Down
36 changes: 26 additions & 10 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13210,18 +13210,14 @@ bool ConstraintSystem::simplifyAppliedOverloadsImpl(

/// The common result type amongst all function overloads.
Type commonResultType;
auto updateCommonResultType = [&](Type choiceType) {
auto markFailure = [&] {
commonResultType = ErrorType::get(getASTContext());
};

auto choiceFnType = choiceType->getAs<FunctionType>();
if (!choiceFnType)
return markFailure();
auto markFailure = [&] {
commonResultType = ErrorType::get(getASTContext());
};

auto updateCommonResultType = [&](Type choiceResultType) {
// For now, don't attempt to establish a common result type when there
// are type parameters.
Type choiceResultType = choiceFnType->getResult();
if (choiceResultType->hasTypeParameter())
return markFailure();

Expand Down Expand Up @@ -13359,8 +13355,28 @@ bool ConstraintSystem::simplifyAppliedOverloadsImpl(
choiceType = objectType;
}

// If we have a function type, we can compute a common result type.
updateCommonResultType(choiceType);
if (auto *choiceFnType = choiceType->getAs<FunctionType>()) {
if (isa<ConstructorDecl>(choice.getDecl())) {
auto choiceResultType = choice.getBaseType()
->getRValueType()
->getMetatypeInstanceType();

if (choiceResultType->getOptionalObjectType()) {
hasUnhandledConstraints = true;
return true;
}

if (choiceFnType->getResult()->getOptionalObjectType())
choiceResultType = OptionalType::get(choiceResultType);

updateCommonResultType(choiceResultType);
} else {
updateCommonResultType(choiceFnType->getResult());
}
} else {
markFailure();
}

return true;
});

Expand Down
4 changes: 3 additions & 1 deletion lib/Sema/MiscDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6800,13 +6800,15 @@ TypeChecker::omitNeedlessWords(AbstractFunctionDecl *afd) {
// Handle contextual type, result type, and returnsSelf.
Type contextType = afd->getDeclContext()->getDeclaredInterfaceType();
Type resultType;
bool returnsSelf = afd->hasDynamicSelfResult();
bool returnsSelf;

if (auto func = dyn_cast<FuncDecl>(afd)) {
resultType = func->getResultInterfaceType();
resultType = func->mapTypeIntoContext(resultType);
returnsSelf = func->getResultInterfaceType()->hasDynamicSelfType();
} else if (isa<ConstructorDecl>(afd)) {
resultType = contextType;
returnsSelf = true;
}

// Figure out the first parameter name.
Expand Down
46 changes: 23 additions & 23 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6641,21 +6641,21 @@ typecheckDifferentiableAttrforDecl(AbstractFunctionDecl *original,
// Dynamic `Self` is supported only as a single top-level result for class
// members. JVP/VJP functions returning `(Self, ...)` tuples would not
// type-check.
bool diagnoseDynamicSelfResult = original->hasDynamicSelfResult();
if (diagnoseDynamicSelfResult) {
// Diagnose class initializers in non-final classes.
if (isa<ConstructorDecl>(original)) {
if (!classDecl->isSemanticallyFinal()) {
diags.diagnose(
attr->getLocation(),
diag::differentiable_attr_nonfinal_class_init_unsupported,
classDecl->getDeclaredInterfaceType());
attr->setInvalid();
return nullptr;
}
// Diagnose class initializers in non-final classes.
if (isa<ConstructorDecl>(original)) {
if (!classDecl->isSemanticallyFinal()) {
diags.diagnose(
attr->getLocation(),
diag::differentiable_attr_nonfinal_class_init_unsupported,
classDecl->getDeclaredInterfaceType());
attr->setInvalid();
return nullptr;
}
}

if (auto *funcDecl = dyn_cast<FuncDecl>(original)) {
// Diagnose all other declarations returning dynamic `Self`.
else {
if (funcDecl->getResultInterfaceType()->hasDynamicSelfType()) {
diags.diagnose(
attr->getLocation(),
diag::
Expand Down Expand Up @@ -7035,19 +7035,19 @@ static bool typeCheckDerivativeAttr(DerivativeAttr *attr) {
// Dynamic `Self` is supported only as a single top-level result for class
// members. JVP/VJP functions returning `(Self, ...)` tuples would not
// type-check.
bool diagnoseDynamicSelfResult = originalAFD->hasDynamicSelfResult();
if (diagnoseDynamicSelfResult) {
if (isa<ConstructorDecl>(originalAFD)) {
// Diagnose class initializers in non-final classes.
if (isa<ConstructorDecl>(originalAFD)) {
if (!classDecl->isSemanticallyFinal()) {
diags.diagnose(attr->getLocation(),
diag::derivative_attr_nonfinal_class_init_unsupported,
classDecl->getDeclaredInterfaceType());
return true;
}
if (!classDecl->isSemanticallyFinal()) {
diags.diagnose(attr->getLocation(),
diag::derivative_attr_nonfinal_class_init_unsupported,
classDecl->getDeclaredInterfaceType());
return true;
}
}

if (auto *FD = dyn_cast<FuncDecl>(originalAFD)) {
// Diagnose all other declarations returning dynamic `Self`.
else {
if (FD->getResultInterfaceType()->hasDynamicSelfType()) {
diags.diagnose(
attr->getLocation(),
diag::derivative_attr_class_member_dynamic_self_result_unsupported,
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,7 @@ bool swift::isRepresentableInLanguage(

// The completion handler transformation cannot properly represent a
// dynamic 'Self' type, so disallow @objc for such methods.
if (FD->hasDynamicSelfResult()) {
if (FD->getResultInterfaceType()->hasDynamicSelfType()) {
AFD->diagnose(diag::async_objc_dynamic_self)
.highlight(AFD->getAsyncLoc())
.limitBehavior(behavior);
Expand Down
6 changes: 4 additions & 2 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4246,8 +4246,10 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
// by holding onto Self accordingly.
if (witness->getDeclContext()->getSelfClassDecl()) {
const bool hasDynamicSelfResult = [&] {
if (auto func = dyn_cast<AbstractFunctionDecl>(witness)) {
return func->hasDynamicSelfResult();
if (isa<ConstructorDecl>(witness)) {
return true;
} else if (auto func = dyn_cast<FuncDecl>(witness)) {
return func->getResultInterfaceType()->hasDynamicSelfType();
} else if (auto var = dyn_cast<VarDecl>(witness)) {
return var->getInterfaceType()->hasDynamicSelfType();
}
Expand Down
Loading