diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index ac78b00eb44a8..910f0674dc0e8 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -1350,10 +1350,6 @@ class alignas(1 << TypeAlignInBits) TypeBase /// Hack to deal with ConstructorDecl interface types. Type withCovariantResultType(); - /// Deprecated in favor of the above. - Type replaceCovariantResultType(Type newResultType, - unsigned uncurryLevel); - /// Returns a new function type exactly like this one but with the self /// parameter replaced. Only makes sense for function members of types. Type replaceSelfParameterType(Type newSelf); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index f31c50f94fa17..9400df841e23d 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1393,37 +1393,6 @@ Type TypeBase::withCovariantResultType() { fnType->getExtInfo()); } -Type TypeBase::replaceCovariantResultType(Type newResultType, - unsigned uncurryLevel) { - if (uncurryLevel == 0) { - bool isLValue = is(); - - auto loadedTy = getWithoutSpecifierType(); - if (auto objectType = loadedTy->getOptionalObjectType()) { - newResultType = OptionalType::get( - objectType->replaceCovariantResultType(newResultType, uncurryLevel)); - } - - return isLValue ? LValueType::get(newResultType) : newResultType; - } - - // Determine the input and result types of this function. - auto fnType = this->castTo(); - auto inputType = fnType->getParams(); - Type resultType = - fnType->getResult()->replaceCovariantResultType(newResultType, - uncurryLevel - 1); - - // Produce the resulting function type. - if (auto genericFn = dyn_cast(fnType)) { - return GenericFunctionType::get(genericFn->getGenericSignature(), - inputType, resultType, - fnType->getExtInfo()); - } - - return FunctionType::get(inputType, resultType, fnType->getExtInfo()); -} - /// Whether this parameter accepts an unlabeled trailing closure argument /// using the more-restrictive forward-scan rule. static bool allowsUnlabeledTrailingClosureParameter(const ParamDecl *param) { diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index a77a10efcd88d..2ce525f3d72d2 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -1633,6 +1633,203 @@ namespace { return outerThunk; } + Expr *buildStaticCurryThunk(Expr *base, Expr *declRefExpr, + AbstractFunctionDecl *member, + FunctionType *adjustedOpenedType, + ConstraintLocatorBuilder locator, + ConstraintLocatorBuilder memberLocator, + bool openedExistential) { + if (cs.isStaticallyDerivedMetatype(base)) { + // Add a useless ".self" to avoid downstream diagnostics. + base = new (ctx) DotSelfExpr(base, SourceLoc(), base->getEndLoc(), + cs.getType(base)); + cs.setType(base, base->getType()); + + // Skip the code below -- we're not building an extra level of + // call by applying the metatype; instead, the closure we just + // built is the curried reference. + return buildSingleCurryThunk( + base, declRefExpr, member, + adjustedOpenedType, + memberLocator); + } else { + // Add a useless ".self" to avoid downstream diagnostics, in case + // the type ref is still a TypeExpr. + base = new (ctx) DotSelfExpr(base, SourceLoc(), base->getEndLoc(), + cs.getType(base)); + // Introduce a capture variable. + cs.cacheType(base); + solution.setExprTypes(base); + auto capture = new (ctx) VarDecl(/*static*/ false, + VarDecl::Introducer::Let, + base->getEndLoc(), + ctx.getIdentifier("$base$"), + dc); + capture->setImplicit(); + capture->setInterfaceType(base->getType()->mapTypeOutOfContext()); + + auto *capturePat = + NamedPattern::createImplicit(ctx, capture, base->getType()); + + auto *captureDecl = PatternBindingDecl::createImplicit( + ctx, StaticSpellingKind::None, capturePat, base, dc); + + // Write the closure in terms of the capture. + auto baseRef = new (ctx) + DeclRefExpr(capture, DeclNameLoc(base->getLoc()), /*implicit*/ true); + baseRef->setType(base->getType()); + cs.cacheType(baseRef); + + auto *closure = buildSingleCurryThunk( + baseRef, declRefExpr, member, + adjustedOpenedType, + memberLocator); + + // Wrap the closure in a capture list. + auto captureEntry = CaptureListEntry(captureDecl); + auto captureExpr = CaptureListExpr::create(ctx, captureEntry, + closure); + captureExpr->setImplicit(); + captureExpr->setType(cs.getType(closure)); + cs.cacheType(captureExpr); + + Expr *finalExpr = captureExpr; + closeExistentials(finalExpr, locator, + /*force*/ openedExistential); + return finalExpr; + } + } + + Expr *buildDynamicMemberRef(Expr *base, Type baseTy, + SourceLoc dotLoc, + ConcreteDeclRef memberRef, + Type openedType, + Type adjustedOpenedType, + DeclNameLoc memberLoc, + ConstraintLocatorBuilder locator, + ConstraintLocatorBuilder memberLocator, + bool openedExistential, + bool Implicit) { + base = cs.coerceToRValue(base); + Expr *ref = new (ctx) DynamicMemberRefExpr(base, dotLoc, memberRef, + memberLoc); + ref->setImplicit(Implicit); + // FIXME: FunctionRefInfo + + // Compute the type of the reference. + auto computeRefType = [&](Type refType) { + // If the base was an opened existential, erase the opened + // existential. + if (openedExistential) { + refType = typeEraseOpenedArchetypesFromEnvironment( + refType, baseTy->castTo()->getGenericEnvironment()); + } + + return refType; + }; + + Type refType = computeRefType(openedType); + cs.setType(ref, refType); + + // Adjust the declaration reference type, if required. + ref = adjustTypeForDeclReference( + ref, openedType, adjustedOpenedType, locator, computeRefType); + + closeExistentials(ref, locator, /*force=*/openedExistential); + + // We also need to handle the implicitly unwrap of the result + // of the called function if that's the type checking solution + // we ended up with. + return forceUnwrapIfExpected(ref, memberLocator); + } + + Expr *buildVarMemberRef(Expr *base, SourceLoc dotLoc, + bool baseIsInstance, + ConcreteDeclRef memberRef, + DeclNameLoc memberLoc, + Type containerTy, + Type refTy, + Type adjustedRefTy, + Type adjustedOpenedType, + AccessSemantics semantics, + ConstraintLocatorBuilder locator, + ConstraintLocatorBuilder memberLocator, + bool isSuper, + bool isUnboundInstanceMember, + bool Implicit) { + auto *varDecl = cast(memberRef.getDecl()); + + bool loadImmediately = false; + auto resultType = [&loadImmediately](Type fnTy) -> Type { + Type resultTy = fnTy->castTo()->getResult(); + if (loadImmediately) + return LValueType::get(resultTy); + return resultTy; + }; + + // If we have an instance property that's treated as an rvalue + // but allows assignment (for initialization) in the current + // context, treat it as an rvalue that we immediately load. + // This is the AST that's expected by SILGen. + if (baseIsInstance && !resultType(refTy)->hasLValueType() && + varDecl->mutability(dc, dyn_cast(base)) + == StorageMutability::Initializable) { + loadImmediately = true; + } + + if (isUnboundInstanceMember) { + assert(memberLocator.getBaseLocator() && + cs.UnevaluatedRootExprs.count( + getAsExpr(memberLocator.getBaseLocator()->getAnchor())) && + "Attempt to reference an instance member of a metatype"); + auto baseInstanceTy = cs.getType(base) + ->getInOutObjectType()->getMetatypeInstanceType(); + base = new (ctx) UnevaluatedInstanceExpr(base, baseInstanceTy); + cs.cacheType(base); + base->setImplicit(); + } + + const auto hasDynamicSelf = refTy->hasDynamicSelfType(); + + auto memberRefExpr + = new (ctx) MemberRefExpr(base, dotLoc, memberRef, + memberLoc, Implicit, semantics); + memberRefExpr->setIsSuper(isSuper); + + if (hasDynamicSelf) { + refTy = refTy->replaceDynamicSelfType(containerTy); + adjustedRefTy = adjustedRefTy->replaceDynamicSelfType( + containerTy); + } + + cs.setType(memberRefExpr, resultType(refTy)); + + Expr *result = memberRefExpr; + result = adjustTypeForDeclReference(result, resultType(refTy), + resultType(adjustedRefTy), + locator); + closeExistentials(result, locator); + + // If the property is of dynamic 'Self' type, wrap an implicit + // conversion around the resulting expression, with the destination + // type having 'Self' swapped for the appropriate replacement + // type -- usually the base object type. + if (hasDynamicSelf) { + const auto conversionTy = adjustedOpenedType; + if (!containerTy->isEqual(conversionTy)) { + result = cs.cacheType(new (ctx) CovariantReturnConversionExpr( + result, conversionTy)); + } + } + + // If we need to load, do so now. + if (loadImmediately) { + result = cs.addImplicitLoadExpr(result); + } + + return forceUnwrapIfExpected(result, memberLocator); + } + /// Build a new member reference with the given base and member. Expr *buildMemberRef(Expr *base, SourceLoc dotLoc, SelectedOverload overload, DeclNameLoc memberLoc, @@ -1704,20 +1901,20 @@ namespace { // This can occur in code that does something like: 'type(of: x).a' where // 'a' is the static value generic member. if (auto gp = dyn_cast(member)) { - if (gp->isValue()) { - auto refType = adjustedOpenedType; - auto ref = TypeValueExpr::createForDecl(memberLoc, gp, dc); - cs.setType(ref, refType); - - auto gpTy = gp->getDeclaredInterfaceType(); - auto subs = baseTy->getContextSubstitutionMap(); - ref->setParamType(gpTy.subst(subs)); - - auto result = new (ctx) DotSyntaxBaseIgnoredExpr(base, dotLoc, ref, - refType); - cs.setType(result, refType); - return result; - } + ASSERT(gp->isValue()); + + auto refType = adjustedOpenedType; + auto ref = TypeValueExpr::createForDecl(memberLoc, gp, dc); + cs.setType(ref, refType); + + auto gpTy = gp->getDeclaredInterfaceType(); + auto subs = baseTy->getContextSubstitutionMap(); + ref->setParamType(gpTy.subst(subs)); + + auto result = new (ctx) DotSyntaxBaseIgnoredExpr(base, dotLoc, ref, + refType); + cs.setType(result, refType); + return result; } // If we're referring to a member type, it's just a type @@ -1857,118 +2054,31 @@ namespace { // Handle dynamic references. if (!needsCurryThunk && (isDynamic || member->getAttrs().hasAttribute())) { - base = cs.coerceToRValue(base); - Expr *ref = new (ctx) DynamicMemberRefExpr(base, dotLoc, memberRef, - memberLoc); - ref->setImplicit(Implicit); - // FIXME: FunctionRefInfo - - // Compute the type of the reference. - auto computeRefType = [&](Type refType) { - // If the base was an opened existential, erase the opened - // existential. - if (openedExistential) { - refType = typeEraseOpenedArchetypesFromEnvironment( - refType, baseTy->castTo()->getGenericEnvironment()); - } - - return refType; - }; - - Type refType = computeRefType(openedType); - cs.setType(ref, refType); - - // Adjust the declaration reference type, if required. - ref = adjustTypeForDeclReference( - ref, openedType, adjustedOpenedType, locator, computeRefType); - - closeExistentials(ref, locator, /*force=*/openedExistential); - - // We also need to handle the implicitly unwrap of the result - // of the called function if that's the type checking solution - // we ended up with. - return forceUnwrapIfExpected(ref, memberLocator); + return buildDynamicMemberRef(base, baseTy, dotLoc, memberRef, + openedType, adjustedOpenedType, + memberLoc, locator, memberLocator, + openedExistential, Implicit); } // For properties, build member references. - if (auto *varDecl = dyn_cast(member)) { - // \returns result of the given function type - bool loadImmediately = false; - auto resultType = [&loadImmediately](Type fnTy) -> Type { - Type resultTy = fnTy->castTo()->getResult(); - if (loadImmediately) - return LValueType::get(resultTy); - return resultTy; - }; - - // If we have an instance property that's treated as an rvalue - // but allows assignment (for initialization) in the current - // context, treat it as an rvalue that we immediately load. - // This is the AST that's expected by SILGen. - if (baseIsInstance && !resultType(refTy)->hasLValueType() && - varDecl->mutability(dc, dyn_cast(base)) - == StorageMutability::Initializable) { - loadImmediately = true; - } - - if (isUnboundInstanceMember) { - assert(memberLocator.getBaseLocator() && - cs.UnevaluatedRootExprs.count( - getAsExpr(memberLocator.getBaseLocator()->getAnchor())) && - "Attempt to reference an instance member of a metatype"); - auto baseInstanceTy = cs.getType(base) - ->getInOutObjectType()->getMetatypeInstanceType(); - base = new (ctx) UnevaluatedInstanceExpr(base, baseInstanceTy); - cs.cacheType(base); - base->setImplicit(); - } - - const auto hasDynamicSelf = refTy->hasDynamicSelfType(); - - auto memberRefExpr - = new (ctx) MemberRefExpr(base, dotLoc, memberRef, - memberLoc, Implicit, semantics); - memberRefExpr->setIsSuper(isSuper); - - if (hasDynamicSelf) { - refTy = refTy->replaceDynamicSelfType(containerTy); - adjustedRefTy = adjustedRefTy->replaceDynamicSelfType( - containerTy); - } - - cs.setType(memberRefExpr, resultType(refTy)); - - Expr *result = memberRefExpr; - result = adjustTypeForDeclReference(result, resultType(refTy), - resultType(adjustedRefTy), - locator); - closeExistentials(result, locator); - - // If the property is of dynamic 'Self' type, wrap an implicit - // conversion around the resulting expression, with the destination - // type having 'Self' swapped for the appropriate replacement - // type -- usually the base object type. - if (hasDynamicSelf) { - const auto conversionTy = adjustedOpenedType; - if (!containerTy->isEqual(conversionTy)) { - result = cs.cacheType(new (ctx) CovariantReturnConversionExpr( - result, conversionTy)); - } - } + if (isa(member)) { + return buildVarMemberRef(base, dotLoc, baseIsInstance, + memberRef, memberLoc, containerTy, + refTy, adjustedRefTy, adjustedOpenedType, + semantics, locator, memberLocator, + isSuper, isUnboundInstanceMember, Implicit); + } - // If we need to load, do so now. - if (loadImmediately) { - result = cs.addImplicitLoadExpr(result); - } + ASSERT(isa(member) || + isa(member)); - return forceUnwrapIfExpected(result, memberLocator); - } + Type refTySelf = refTy, adjustedRefTySelf = adjustedRefTy; auto *func = dyn_cast(member); if (func && func->getResultInterfaceType()->hasDynamicSelfType()) { ASSERT(refTy->hasDynamicSelfType()); - refTy = refTy->replaceDynamicSelfType(containerTy); - adjustedRefTy = adjustedRefTy->replaceDynamicSelfType( + refTySelf = refTy->replaceDynamicSelfType(containerTy); + adjustedRefTySelf = adjustedRefTy->replaceDynamicSelfType( containerTy); } @@ -1976,11 +2086,11 @@ namespace { auto declRefExpr = new (ctx) DeclRefExpr(memberRef, memberLoc, Implicit, semantics); declRefExpr->setFunctionRefInfo(choice.getFunctionRefInfo()); - declRefExpr->setType(refTy); - cs.setType(declRefExpr, refTy); + declRefExpr->setType(refTySelf); + cs.setType(declRefExpr, refTySelf); Expr *ref = declRefExpr; - ref = adjustTypeForDeclReference(ref, refTy, adjustedRefTy, locator); + ref = adjustTypeForDeclReference(ref, refTySelf, adjustedRefTySelf, locator); // A partial application thunk consists of two nested closures: // @@ -2015,65 +2125,10 @@ namespace { // or to evaluate the base as a capture and hand it down via the // capture list. if (isa(member) || member->isStatic()) { - if (cs.isStaticallyDerivedMetatype(base)) { - // Add a useless ".self" to avoid downstream diagnostics. - base = new (ctx) DotSelfExpr(base, SourceLoc(), base->getEndLoc(), - cs.getType(base)); - cs.setType(base, base->getType()); - - // Skip the code below -- we're not building an extra level of - // call by applying the metatype; instead, the closure we just - // built is the curried reference. - return buildSingleCurryThunk( - base, declRefExpr, cast(member), - adjustedOpenedType->castTo(), - memberLocator); - } else { - // Add a useless ".self" to avoid downstream diagnostics, in case - // the type ref is still a TypeExpr. - base = new (ctx) DotSelfExpr(base, SourceLoc(), base->getEndLoc(), - cs.getType(base)); - // Introduce a capture variable. - cs.cacheType(base); - solution.setExprTypes(base); - auto capture = new (ctx) VarDecl(/*static*/ false, - VarDecl::Introducer::Let, - base->getEndLoc(), - ctx.getIdentifier("$base$"), - dc); - capture->setImplicit(); - capture->setInterfaceType(base->getType()->mapTypeOutOfContext()); - - auto *capturePat = - NamedPattern::createImplicit(ctx, capture, base->getType()); - - auto *captureDecl = PatternBindingDecl::createImplicit( - ctx, StaticSpellingKind::None, capturePat, base, dc); - - // Write the closure in terms of the capture. - auto baseRef = new (ctx) - DeclRefExpr(capture, DeclNameLoc(base->getLoc()), /*implicit*/ true); - baseRef->setType(base->getType()); - cs.cacheType(baseRef); - - auto *closure = buildSingleCurryThunk( - baseRef, declRefExpr, cast(member), + return buildStaticCurryThunk( + base, declRefExpr, cast(member), adjustedOpenedType->castTo(), - memberLocator); - - // Wrap the closure in a capture list. - auto captureEntry = CaptureListEntry(captureDecl); - auto captureExpr = CaptureListExpr::create(ctx, captureEntry, - closure); - captureExpr->setImplicit(); - captureExpr->setType(cs.getType(closure)); - cs.cacheType(captureExpr); - - Expr *finalExpr = captureExpr; - closeExistentials(finalExpr, locator, - /*force*/ openedExistential); - return finalExpr; - } + locator, memberLocator, openedExistential); } FunctionType *curryThunkTy = nullptr; @@ -2087,7 +2142,7 @@ namespace { // on 'CovariantReturnConversionExpr'. curryThunkTy = adjustedOpenedType->castTo(); } else { - curryThunkTy = adjustedRefTy->castTo(); + curryThunkTy = adjustedRefTySelf->castTo(); // Check if we need to open an existential stored inside 'self'. auto knownOpened = solution.OpenedExistentialTypes.find( @@ -2123,8 +2178,13 @@ namespace { const Type replacementTy = getDynamicSelfReplacementType( baseTy, member, memberLocator.getBaseLocator()); if (!replacementTy->isEqual(containerTy)) { + if (isa(member)) { + adjustedRefTy = adjustedRefTy->withCovariantResultType(); + } else { + ASSERT(adjustedRefTy->hasDynamicSelfType()); + } Type conversionTy = - adjustedRefTy->replaceCovariantResultType(replacementTy, 2); + adjustedRefTy->replaceDynamicSelfType(replacementTy); if (isSuperPartialApplication) { conversionTy = conversionTy->castTo()->getResult();