mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Sema: Rewrite witness method calls as ApplyExpr + DeclRefExpr
Special-casing these as MemberRefExprs created an asymmetry where unbound archetype instance methods (<T : P> T.f) could not be represented. Treating class and protocol methods uniformly also eliminates a handful of special cases around MemberRefExpr. SILGen's RValue and call emission peepholes now have to know about DeclRefExprs that point to protocol methods. Finally, generalize the diagnostic for partially applied mutating methods to any partially applied function with an inout parameter, since this is not supported. Fixes <rdar://problem/20564672>. Swift SVN r29298
This commit is contained in:
@@ -1548,9 +1548,11 @@ ERROR(ambiguous_decl_ref,tce_sema,none,
|
||||
ERROR(ambiguous_operator_ref,tce_sema,none,
|
||||
"ambiguous use of operator %0", (Identifier))
|
||||
|
||||
ERROR(partial_application_of_method_invalid,tce_sema,none,
|
||||
"partial application of 'mutating' %select{struct method|enum method|"
|
||||
"generic method|protocol method}0 is not allowed",
|
||||
// Cannot capture inout-ness of a parameter
|
||||
// Partial application of foreign functions not supported
|
||||
ERROR(partial_application_of_function_invalid,tce_sema,none,
|
||||
"partial application of %select{function with 'inout' parameters|"
|
||||
"'mutating' method|method in @objc protocol}0 is not allowed",
|
||||
(unsigned))
|
||||
|
||||
ERROR(self_assignment_var,tce_sema,none,
|
||||
|
||||
@@ -708,7 +708,7 @@ namespace {
|
||||
static Callee prepareArchetypeCallee(SILGenFunction &gen, SILLocation loc,
|
||||
SILDeclRef constant,
|
||||
ArgumentSource &selfValue,
|
||||
CanAnyFunctionType substAccessorType,
|
||||
CanAnyFunctionType substFnType,
|
||||
ArrayRef<Substitution> &substitutions) {
|
||||
auto fd = cast<AbstractFunctionDecl>(constant.getDecl());
|
||||
auto protocol = cast<ProtocolDecl>(fd->getDeclContext());
|
||||
@@ -798,8 +798,11 @@ static Callee prepareArchetypeCallee(SILGenFunction &gen, SILLocation loc,
|
||||
|
||||
materializeSelfIfNecessary();
|
||||
|
||||
// The protocol self is implicitly decurried.
|
||||
substFnType = cast<AnyFunctionType>(substFnType.getResult());
|
||||
|
||||
return Callee::forArchetype(gen, openingSite, selfTy,
|
||||
constant, substAccessorType, loc);
|
||||
constant, substFnType, loc);
|
||||
}
|
||||
|
||||
/// An ASTVisitor for building SIL function calls.
|
||||
@@ -915,7 +918,8 @@ public:
|
||||
for (auto callSite : CallSites) {
|
||||
addSite(callSite, false);
|
||||
}
|
||||
// The self application might be a MemberRefExpr if "self" is an archetype.
|
||||
|
||||
// The self application might be a DynamicMemberRefExpr.
|
||||
if (auto selfApply = dyn_cast_or_null<ApplyExpr>(SelfApplyExpr)) {
|
||||
addSite(selfApply, otherCtorRefUsesAllocating);
|
||||
}
|
||||
@@ -1022,6 +1026,68 @@ public:
|
||||
bool requiresAllocRefDynamic = false;
|
||||
|
||||
// Determine whether the method is dynamically dispatched.
|
||||
if (auto *proto = dyn_cast<ProtocolDecl>(afd->getDeclContext())) {
|
||||
// We have four cases to deal with here:
|
||||
//
|
||||
// 1) for a "static" / "type" method, the base is a metatype.
|
||||
// 2) for a classbound protocol, the base is a class-bound protocol rvalue,
|
||||
// which is loadable.
|
||||
// 3) for a mutating method, the base has inout type.
|
||||
// 4) for a nonmutating method, the base is a general archetype
|
||||
// rvalue, which is address-only. The base is passed at +0, so it isn't
|
||||
// consumed.
|
||||
//
|
||||
// In the last case, the AST has this call typed as being applied
|
||||
// to an rvalue, but the witness is actually expecting a pointer
|
||||
// to the +0 value in memory. We just pass in the address since
|
||||
// archetypes are address-only.
|
||||
|
||||
CanAnyFunctionType substFnType = getSubstFnType();
|
||||
assert(!CallSites.empty());
|
||||
ApplyExpr *thisCallSite = CallSites.back();
|
||||
CallSites.pop_back();
|
||||
|
||||
ArgumentSource selfValue = thisCallSite->getArg();
|
||||
|
||||
ArrayRef<Substitution> subs = e->getDeclRef().getSubstitutions();
|
||||
|
||||
SILDeclRef::Kind kind = SILDeclRef::Kind::Func;
|
||||
if (isa<ConstructorDecl>(afd)) {
|
||||
if (proto->isObjC()) {
|
||||
SILLocation loc = thisCallSite->getArg();
|
||||
|
||||
// For Objective-C initializers, we only have an initializing
|
||||
// initializer. We need to allocate the object ourselves.
|
||||
kind = SILDeclRef::Kind::Initializer;
|
||||
|
||||
auto metatype = std::move(selfValue).getAsSingleValue(SGF);
|
||||
auto allocated = allocateObjCObject(metatype, loc);
|
||||
auto allocatedType = allocated.getType().getSwiftRValueType();
|
||||
selfValue = ArgumentSource(loc, RValue(allocated, allocatedType));
|
||||
} else {
|
||||
// For non-Objective-C initializers, we have an allocating
|
||||
// initializer to call.
|
||||
kind = SILDeclRef::Kind::Allocator;
|
||||
}
|
||||
}
|
||||
|
||||
SILDeclRef constant = SILDeclRef(afd, kind);
|
||||
|
||||
// Prepare the callee. This can modify both selfValue and subs.
|
||||
Callee theCallee = prepareArchetypeCallee(SGF, e, constant, selfValue,
|
||||
substFnType, subs);
|
||||
|
||||
setSelfParam(std::move(selfValue), thisCallSite);
|
||||
setCallee(std::move(theCallee));
|
||||
|
||||
// If there are substitutions, add them now.
|
||||
if (!subs.empty()) {
|
||||
ApplyCallee->setSubstitutions(SGF, e, subs, CallDepth);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->getAccessSemantics() != AccessSemantics::Ordinary) {
|
||||
isDynamicallyDispatched = false;
|
||||
} else {
|
||||
@@ -1222,78 +1288,6 @@ public:
|
||||
return subs.slice(innerIdx);
|
||||
}
|
||||
|
||||
void visitMemberRefExpr(MemberRefExpr *e) {
|
||||
auto *fd = dyn_cast<AbstractFunctionDecl>(e->getMember().getDecl());
|
||||
|
||||
// If the base is a non-protocol, non-archetype type, then this is a load of
|
||||
// a function pointer out of a vardecl. Just emit it as an rvalue.
|
||||
if (!fd)
|
||||
return visitExpr(e);
|
||||
|
||||
// We have four cases to deal with here:
|
||||
//
|
||||
// 1) for a "static" / "type" method, the base is a metatype.
|
||||
// 2) for a classbound protocol, the base is a class-bound protocol rvalue,
|
||||
// which is loadable.
|
||||
// 3) for a mutating method, the base has inout type.
|
||||
// 4) for a nonmutating method, the base is a general archetype
|
||||
// rvalue, which is address-only. The base is passed at +0, so it isn't
|
||||
// consumed.
|
||||
//
|
||||
// In the last case, the AST has this call typed as being applied
|
||||
// to an rvalue, but the witness is actually expecting a pointer
|
||||
// to the +0 value in memory. We just pass in the address since
|
||||
// archetypes are address-only.
|
||||
|
||||
ArgumentSource selfValue = e->getBase();
|
||||
|
||||
auto *proto = cast<ProtocolDecl>(fd->getDeclContext());
|
||||
ArrayRef<Substitution> subs = e->getMember().getSubstitutions();
|
||||
|
||||
// Figure out the kind of declaration reference we're working with.
|
||||
SILDeclRef::Kind kind = SILDeclRef::Kind::Func;
|
||||
if (isa<ConstructorDecl>(fd)) {
|
||||
if (proto->isObjC()) {
|
||||
// For Objective-C initializers, we only have an initializing
|
||||
// initializer. We need to allocate the object ourselves.
|
||||
kind = SILDeclRef::Kind::Initializer;
|
||||
|
||||
auto metatype = std::move(selfValue).getAsSingleValue(SGF);
|
||||
auto allocated = allocateObjCObject(metatype, e->getBase());
|
||||
auto allocatedType = allocated.getType().getSwiftRValueType();
|
||||
selfValue = ArgumentSource(e->getBase(),
|
||||
RValue(allocated, allocatedType));
|
||||
|
||||
} else {
|
||||
// For non-Objective-C initializers, we have an allocating
|
||||
// initializer to call.
|
||||
kind = SILDeclRef::Kind::Allocator;
|
||||
}
|
||||
}
|
||||
SILDeclRef constant = SILDeclRef(fd, kind);
|
||||
|
||||
// Gross. We won't have any call sites if this is a curried generic method
|
||||
// application, because it doesn't look like a call site in the AST, but a
|
||||
// member ref.
|
||||
CanFunctionType substFnType;
|
||||
if (!CallSites.empty() || dyn_cast_or_null<ApplyExpr>(SelfApplyExpr))
|
||||
substFnType = getSubstFnType();
|
||||
else
|
||||
substFnType = cast<FunctionType>(e->getType()->getCanonicalType());
|
||||
|
||||
// Prepare the callee. This can modify both selfValue and subs.
|
||||
Callee theCallee = prepareArchetypeCallee(SGF, e, constant, selfValue,
|
||||
substFnType, subs);
|
||||
|
||||
setSelfParam(std::move(selfValue), e);
|
||||
setCallee(std::move(theCallee));
|
||||
|
||||
// If there are substitutions, add them now.
|
||||
if (!subs.empty()) {
|
||||
ApplyCallee->setSubstitutions(SGF, e, subs, CallDepth);
|
||||
}
|
||||
}
|
||||
|
||||
void visitFunctionConversionExpr(FunctionConversionExpr *e) {
|
||||
// FIXME: Check whether this function conversion requires us to build a
|
||||
// thunk.
|
||||
@@ -3451,9 +3445,6 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &gen,
|
||||
assert(!isDirectUse && "direct use of protocol accessor?");
|
||||
assert(!isSuper && "super call to protocol method?");
|
||||
|
||||
// The protocol self is implicitly decurried.
|
||||
substAccessorType = cast<AnyFunctionType>(substAccessorType.getResult());
|
||||
|
||||
return prepareArchetypeCallee(gen, loc, constant, selfValue,
|
||||
substAccessorType, substitutions);
|
||||
}
|
||||
|
||||
@@ -1803,13 +1803,6 @@ RValue RValueEmitter::visitMemberRefExpr(MemberRefExpr *E, SGFContext C) {
|
||||
SGF.B.createMetatype(E, SGF.getLoweredLoadableType(E->getType()));
|
||||
return RValue(SGF, E, ManagedValue::forUnmanaged(MT));
|
||||
}
|
||||
|
||||
if (isa<AbstractFunctionDecl>(E->getMember().getDecl())) {
|
||||
// Method references into generics are represented as member refs instead
|
||||
// of apply exprs for some reason. Send this down the correct path to be
|
||||
// treated as a curried method application.
|
||||
return SGF.emitApplyExpr(E, C);
|
||||
}
|
||||
|
||||
// If we have a nominal type decl as our base, try to use special logic to
|
||||
// emit the base rvalue's member using special logic that will let us avoid
|
||||
|
||||
@@ -472,7 +472,7 @@ namespace {
|
||||
locator, locator, implicit, semantics,
|
||||
/*isDynamic=*/false);
|
||||
if (!result)
|
||||
return nullptr;;
|
||||
return nullptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -967,11 +967,11 @@ namespace {
|
||||
return ref;
|
||||
}
|
||||
|
||||
// For types, properties, and members of archetypes, build
|
||||
// member references.
|
||||
if (isDependentConformingRef || isa<TypeDecl>(member) ||
|
||||
isa<VarDecl>(member)) {
|
||||
// For types and properties, build member references.
|
||||
if (isa<TypeDecl>(member) || isa<VarDecl>(member)) {
|
||||
assert(!dynamicSelfFnType && "Converted type doesn't make sense here");
|
||||
assert(baseIsInstance || !member->isInstanceMember());
|
||||
|
||||
auto memberRefExpr
|
||||
= new (context) MemberRefExpr(base, dotLoc, memberRef,
|
||||
memberLoc, Implicit, semantics);
|
||||
@@ -2226,7 +2226,9 @@ namespace {
|
||||
newRef = convertUnavailableToOptional(newRef,decl, expr->getLoc(),
|
||||
choice.getReasonUnavailable(cs));
|
||||
}
|
||||
|
||||
|
||||
recordUnsupportedPartialApply(expr, newRef);
|
||||
|
||||
return newRef;
|
||||
}
|
||||
|
||||
@@ -2360,7 +2362,10 @@ namespace {
|
||||
locator, expr->isSpecialized(),
|
||||
expr->isImplicit(),
|
||||
AccessSemantics::Ordinary);
|
||||
|
||||
|
||||
if (auto newDeclRef = dyn_cast<DeclRefExpr>(newRef))
|
||||
recordUnsupportedPartialApply(newDeclRef, newDeclRef);
|
||||
|
||||
if (choice.isPotentiallyUnavailable()) {
|
||||
newRef = convertUnavailableToOptional(newRef, decl, expr->getLoc(),
|
||||
choice.getReasonUnavailable(cs));
|
||||
@@ -2488,23 +2493,22 @@ namespace {
|
||||
}
|
||||
|
||||
private:
|
||||
struct MemberPartialApplication {
|
||||
// Selector for the partial_application_of_function_invalid diagnostic
|
||||
// message.
|
||||
struct PartialApplication {
|
||||
unsigned level : 29;
|
||||
// Selector for the partial_application_of_method_invalid diagnostic
|
||||
// message.
|
||||
enum : unsigned {
|
||||
Struct,
|
||||
Enum,
|
||||
Archetype,
|
||||
Protocol
|
||||
Function,
|
||||
MutatingMethod,
|
||||
ObjCProtocolMethod
|
||||
};
|
||||
unsigned kind : 3;
|
||||
};
|
||||
|
||||
// A map used to track partial applications of methods to require that they
|
||||
// be fully applied. Partial applications of value types would capture
|
||||
// 'self' as an inout and hide any mutation of 'self', which is surprising.
|
||||
llvm::SmallDenseMap<Expr*, MemberPartialApplication, 2>
|
||||
|
||||
// Partial applications of functions with inout parameters is not permitted,
|
||||
// so we track them to ensure they are fully applied. The map value is the
|
||||
// number of remaining applications.
|
||||
llvm::SmallDenseMap<Expr*, PartialApplication, 2>
|
||||
InvalidPartialApplications;
|
||||
|
||||
/// A list of "suspicious" optional injections that come from
|
||||
@@ -2575,49 +2579,10 @@ namespace {
|
||||
AccessSemantics::Ordinary,
|
||||
isDynamic,
|
||||
reason);
|
||||
|
||||
// If this is an application of a mutating method,
|
||||
// arrange for us to check that it gets fully applied.
|
||||
FuncDecl *fn = nullptr;
|
||||
Optional<unsigned> kind;
|
||||
if (auto apply = dyn_cast<ApplyExpr>(member)) {
|
||||
auto selfInoutTy = apply->getArg()->getType()->getAs<InOutType>();
|
||||
if (!selfInoutTy)
|
||||
goto not_mutating_member;
|
||||
auto selfTy = selfInoutTy->getObjectType();
|
||||
auto fnDeclRef = dyn_cast<DeclRefExpr>(apply->getFn());
|
||||
if (!fnDeclRef)
|
||||
goto not_mutating_member;
|
||||
fn = dyn_cast<FuncDecl>(fnDeclRef->getDecl());
|
||||
if (selfTy->getStructOrBoundGenericStruct())
|
||||
kind = MemberPartialApplication::Struct;
|
||||
else if (selfTy->getEnumOrBoundGenericEnum())
|
||||
kind = MemberPartialApplication::Enum;
|
||||
else
|
||||
goto not_mutating_member;
|
||||
} else if (auto pmRef = dyn_cast<MemberRefExpr>(member)) {
|
||||
auto baseInoutTy = pmRef->getBase()->getType()->getAs<InOutType>();
|
||||
if (!baseInoutTy)
|
||||
goto not_mutating_member;
|
||||
auto baseTy = baseInoutTy->getObjectType();
|
||||
if (baseTy->getRValueType()->isOpenedExistential()) {
|
||||
kind = MemberPartialApplication::Protocol;
|
||||
} else if (baseTy->hasReferenceSemantics()) {
|
||||
goto not_mutating_member;
|
||||
} else if (isa<FuncDecl>(pmRef->getMember().getDecl()))
|
||||
kind = MemberPartialApplication::Archetype;
|
||||
else
|
||||
goto not_mutating_member;
|
||||
fn = dyn_cast<FuncDecl>(pmRef->getMember().getDecl());
|
||||
}
|
||||
|
||||
if (fn && fn->isInstanceMember())
|
||||
InvalidPartialApplications.insert({
|
||||
member,
|
||||
// We need to apply all of the non-self argument clauses.
|
||||
{fn->getNaturalArgumentCount() - 1, kind.getValue() },
|
||||
});
|
||||
not_mutating_member:
|
||||
|
||||
if (auto applyExpr = dyn_cast<ApplyExpr>(member))
|
||||
advancePartialApplyExpr(applyExpr, applyExpr);
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
@@ -2884,29 +2849,107 @@ namespace {
|
||||
llvm_unreachable("Already type-checked");
|
||||
}
|
||||
|
||||
/// If this is an application of a function that cannot be partially
|
||||
/// applied, arrange for us to check that it gets fully applied.
|
||||
void recordUnsupportedPartialApply(DeclRefExpr *expr, Expr *fnExpr) {
|
||||
bool requiresFullApply = false;
|
||||
unsigned kind;
|
||||
|
||||
auto fn = dyn_cast<FuncDecl>(expr->getDecl());
|
||||
if (!fn)
|
||||
return;
|
||||
|
||||
// @objc protocol methods cannot be partially applied.
|
||||
if (auto proto = fn->getDeclContext()->isProtocolOrProtocolExtensionContext()) {
|
||||
if (proto->isObjC()) {
|
||||
requiresFullApply = true;
|
||||
kind = PartialApplication::ObjCProtocolMethod;
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresFullApply) {
|
||||
// We need to apply all argument clauses.
|
||||
InvalidPartialApplications.insert({
|
||||
fnExpr, {fn->getNaturalArgumentCount(), kind}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// If this is an application of a function that cannot be partially
|
||||
/// applied, arrange for us to check that it gets fully applied.
|
||||
void recordUnsupportedPartialApply(ApplyExpr *expr, Expr *fnExpr) {
|
||||
bool requiresFullApply = false;
|
||||
unsigned kind;
|
||||
|
||||
auto fnDeclRef = dyn_cast<DeclRefExpr>(fnExpr);
|
||||
if (!fnDeclRef)
|
||||
return;
|
||||
|
||||
recordUnsupportedPartialApply(fnDeclRef, fnExpr);
|
||||
|
||||
auto fn = dyn_cast<FuncDecl>(fnDeclRef->getDecl());
|
||||
if (!fn)
|
||||
return;
|
||||
|
||||
if (fn->isInstanceMember())
|
||||
kind = PartialApplication::MutatingMethod;
|
||||
else
|
||||
kind = PartialApplication::Function;
|
||||
|
||||
// Functions with inout parameters cannot be partially applied.
|
||||
auto argTy = expr->getArg()->getType();
|
||||
if (auto tupleTy = argTy->getAs<TupleType>()) {
|
||||
for (auto eltTy : tupleTy->getElementTypes()) {
|
||||
if (eltTy->getAs<InOutType>()) {
|
||||
requiresFullApply = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (argTy->getAs<InOutType>()) {
|
||||
requiresFullApply = true;
|
||||
}
|
||||
|
||||
if (requiresFullApply) {
|
||||
// We need to apply all argument clauses.
|
||||
InvalidPartialApplications.insert({
|
||||
fnExpr, {fn->getNaturalArgumentCount(), kind}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// See if this application advanced a partial value type application.
|
||||
void advancePartialApplyExpr(ApplyExpr *expr, Expr *result) {
|
||||
Expr *fnExpr = expr->getFn()->getSemanticsProvidingExpr();
|
||||
if (auto forceExpr = dyn_cast<ForceValueExpr>(fnExpr))
|
||||
fnExpr = forceExpr->getSubExpr()->getSemanticsProvidingExpr();
|
||||
if (auto dotSyntaxExpr = dyn_cast<DotSyntaxBaseIgnoredExpr>(fnExpr))
|
||||
fnExpr = dotSyntaxExpr->getRHS();
|
||||
|
||||
recordUnsupportedPartialApply(expr, fnExpr);
|
||||
|
||||
auto foundApplication = InvalidPartialApplications.find(fnExpr);
|
||||
if (foundApplication == InvalidPartialApplications.end())
|
||||
return;
|
||||
|
||||
unsigned level = foundApplication->second.level;
|
||||
assert(level > 0);
|
||||
InvalidPartialApplications.erase(foundApplication);
|
||||
if (level > 1) {
|
||||
// We have remaining argument clauses.
|
||||
InvalidPartialApplications.insert({
|
||||
result, {level - 1, foundApplication->second.kind}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Expr *visitApplyExpr(ApplyExpr *expr) {
|
||||
auto result = finishApply(expr, expr->getType(),
|
||||
ConstraintLocatorBuilder(
|
||||
cs.getConstraintLocator(expr)));
|
||||
|
||||
// See if this application advanced a partial value type application.
|
||||
Expr *fn = expr->getFn()->getSemanticsProvidingExpr();
|
||||
if (auto force = dyn_cast<ForceValueExpr>(fn))
|
||||
fn = force->getSubExpr()->getSemanticsProvidingExpr();
|
||||
auto foundApplication = InvalidPartialApplications.find(fn);
|
||||
if (foundApplication != InvalidPartialApplications.end()) {
|
||||
unsigned level = foundApplication->second.level;
|
||||
assert(level > 0);
|
||||
InvalidPartialApplications.erase(foundApplication);
|
||||
if (level > 1)
|
||||
InvalidPartialApplications.insert({
|
||||
result, {
|
||||
level - 1,
|
||||
foundApplication->second.kind
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Record a partial value type application, if necessary.
|
||||
advancePartialApplyExpr(expr, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3412,7 +3455,7 @@ namespace {
|
||||
for (auto &unapplied : InvalidPartialApplications) {
|
||||
unsigned kind = unapplied.second.kind;
|
||||
tc.diagnose(unapplied.first->getLoc(),
|
||||
diag::partial_application_of_method_invalid,
|
||||
diag::partial_application_of_function_invalid,
|
||||
kind);
|
||||
}
|
||||
|
||||
|
||||
@@ -1010,14 +1010,7 @@ void ConstraintSystem::openGeneric(
|
||||
/// declared.
|
||||
static void addSelfConstraint(ConstraintSystem &cs, Type objectTy, Type selfTy,
|
||||
ConstraintLocatorBuilder locator){
|
||||
// When referencing a protocol member, we need the object type to be usable
|
||||
// as the Self type of the protocol, which covers anything that conforms to
|
||||
// the protocol as well as existentials that include that protocol.
|
||||
if (selfTy->is<ProtocolType>()) {
|
||||
cs.addConstraint(ConstraintKind::SelfObjectOfProtocol, objectTy, selfTy,
|
||||
cs.getConstraintLocator(locator));
|
||||
return;
|
||||
}
|
||||
assert(!selfTy->is<ProtocolType>());
|
||||
|
||||
// Otherwise, use a subtype constraint for classes to cope with inheritance.
|
||||
if (selfTy->getClassOrBoundGenericClass()) {
|
||||
|
||||
@@ -126,23 +126,16 @@ protocol P {
|
||||
mutating func mut(x: Int)
|
||||
}
|
||||
|
||||
@objc
|
||||
protocol P2 {
|
||||
func bar(x: Int)
|
||||
}
|
||||
|
||||
|
||||
func generic<T: P>(var t: T) {
|
||||
_ = t.bar
|
||||
_ = t.mut // expected-error{{partial application of 'mutating' generic method is not allowed}}
|
||||
_ = t.mut // expected-error{{partial application of 'mutating' method is not allowed}}
|
||||
var _ : () = t.bar(0)
|
||||
}
|
||||
|
||||
func existential(var p: P, p2 : P2) {
|
||||
func existential(var p: P) {
|
||||
p.mut(1)
|
||||
_ = p.bar
|
||||
_ = p.mut // expected-error{{partial application of 'mutating' protocol method is not allowed}}
|
||||
_ = p2.bar
|
||||
_ = p.mut // expected-error{{partial application of 'mutating' method is not allowed}}
|
||||
var _ : () = p.bar(0)
|
||||
}
|
||||
|
||||
|
||||
20
test/Constraints/members_objc.swift
Normal file
20
test/Constraints/members_objc.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
// RUN: %target-parse-verify-swift
|
||||
|
||||
import Swift
|
||||
|
||||
@objc
|
||||
protocol P2 {
|
||||
func bar(x: Int)
|
||||
}
|
||||
|
||||
func existential(p2 : P2) {
|
||||
_ = p2.bar // expected-error{{partial application of method in @objc protocol is not allowed}}
|
||||
}
|
||||
|
||||
func archetype<T: P2>(p2 : T) {
|
||||
_ = p2.bar // expected-error{{partial application of method in @objc protocol is not allowed}}
|
||||
}
|
||||
|
||||
func archetypeMeta<T: P2>(p2 : T) {
|
||||
_ = T.bar // FIXME: not yet diagnosed
|
||||
}
|
||||
@@ -22,3 +22,46 @@ foo(S(offset: 4))
|
||||
let p : P = S(offset: 4)
|
||||
print("\(p.scale(5)(y: 7))\n", appendNewline: false)
|
||||
// CHECK: 39
|
||||
|
||||
func culDeSac<T>(t: T) {}
|
||||
func roundabout<T>(t: T, _ u: T -> ()) { u(t) }
|
||||
|
||||
protocol Proto {
|
||||
typealias Category
|
||||
func f(t: Self)(i: Category, j: Category)
|
||||
static func ff()(i: Category, j: Category)
|
||||
}
|
||||
|
||||
class Q : Proto {
|
||||
typealias Category = Int
|
||||
var q: Int
|
||||
init(q: Int) { self.q = q }
|
||||
func f(t: Q)(i: Int, j: Int) { print(q * t.q + i * j) }
|
||||
static func ff()(i: Int, j: Int) { print(i * j) }
|
||||
}
|
||||
|
||||
func suburbanJungle<T : Proto where T.Category == Int>(t: T) {
|
||||
roundabout(T.ff) { $0()(i: 2, j: 10) }
|
||||
roundabout(T.ff()) { $0(i: 4, j: 10) }
|
||||
culDeSac(T.ff()(i: 6, j: 10))
|
||||
roundabout(T.f) { $0(t)(t)(i: 1, j: 2) }
|
||||
roundabout(T.f(t)) { $0(t)(i: 3, j: 4) }
|
||||
roundabout(T.f(t)(t)) { $0(i: 5, j: 6) }
|
||||
culDeSac(T.f(t)(t)(i: 7, j: 8))
|
||||
roundabout(t.f) { $0(t)(i: 9, j: 10) }
|
||||
roundabout(t.f(t)) { $0(i: 11, j: 12) }
|
||||
culDeSac(t.f(t)(i: 13, j: 14))
|
||||
}
|
||||
|
||||
suburbanJungle(Q(q: 3))
|
||||
|
||||
// CHECK: 20
|
||||
// CHECK: 40
|
||||
// CHECK: 60
|
||||
// CHECK: 11
|
||||
// CHECK: 21
|
||||
// CHECK: 39
|
||||
// CHECK: 65
|
||||
// CHECK: 99
|
||||
// CHECK: 141
|
||||
// CHECK: 191
|
||||
|
||||
@@ -1,15 +1,64 @@
|
||||
// RUN: %target-swift-frontend -emit-silgen %s > /tmp/x.sil
|
||||
// RUN: %target-swift-frontend -emit-silgen %s | FileCheck %s
|
||||
|
||||
protocol Foo {
|
||||
static func foo()
|
||||
static func staticFunc()
|
||||
func instanceFunc()
|
||||
}
|
||||
|
||||
func getFoo<T: Foo>(t: T.Type) -> () -> () {
|
||||
return t.foo
|
||||
// CHECK-LABEL: sil hidden @_TF21partial_apply_generic14getStaticFunc1uRq_S_3Foo_FMq_FT_T_
|
||||
func getStaticFunc1<T: Foo>(t: T.Type) -> () -> () {
|
||||
// CHECK: [[REF:%.*]] = function_ref @_TZFP21partial_apply_generic3Foo10staticFuncuRq_S0__FMq_FT_T_
|
||||
// CHECK-NEXT: apply [[REF]]<T>(%0)
|
||||
return t.staticFunc
|
||||
// CHECK-NEXT: return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden @_TF21partial_apply_generic6getFoouRq_S_3Foo_FMq_FT_T_
|
||||
// CHECK: function_ref @_TZFP21partial_apply_generic3Foo3foouRq_S0__FMq_FT_T_
|
||||
// CHECK-LABEL: sil shared @_TZFP21partial_apply_generic3Foo10staticFuncuRq_S0__FMq_FT_T_
|
||||
// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.staticFunc!1
|
||||
// CHECK-NEXT: partial_apply [[REF]]<Self>(%0)
|
||||
// CHECK-NEXT: return
|
||||
|
||||
// CHECK-LABEL: sil hidden @_TF21partial_apply_generic14getStaticFunc2uRq_S_3Foo_Fq_FT_T_
|
||||
func getStaticFunc2<T: Foo>(t: T) -> () -> () {
|
||||
// CHECK: [[REF:%.*]] = function_ref @_TZFP21partial_apply_generic3Foo10staticFuncuRq_S0__FMq_FT_T_
|
||||
// CHECK: apply [[REF]]<T>
|
||||
return T.staticFunc
|
||||
// CHECK-NEXT: destroy_addr %0 : $*T
|
||||
// CHECK-NEXT: return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden @_TF21partial_apply_generic16getInstanceFunc1uRq_S_3Foo_Fq_FT_T_
|
||||
func getInstanceFunc1<T: Foo>(t: T) -> () -> () {
|
||||
// CHECK: [[REF:%.*]] = function_ref @_TFP21partial_apply_generic3Foo12instanceFuncuRq_S0__Fq_FT_T_
|
||||
// CHECK-NEXT: alloc_stack $T
|
||||
// CHECK-NEXT: copy_addr %0 to [initialization]
|
||||
// CHECK-NEXT: apply [[REF]]<T>
|
||||
return t.instanceFunc
|
||||
// CHECK-NEXT: dealloc_stack
|
||||
// CHECK-NEXT: destroy_addr %0 : $*T
|
||||
// CHECK-NEXT: return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil shared @_TFP21partial_apply_generic3Foo12instanceFuncuRq_S0__Fq_FT_T_
|
||||
// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.instanceFunc!1
|
||||
// CHECK-NEXT: partial_apply [[REF]]<Self>(%0)
|
||||
// CHECK-NEXT: return
|
||||
|
||||
// CHECK-LABEL: sil hidden @_TF21partial_apply_generic16getInstanceFunc2uRq_S_3Foo_Fq_Fq_FT_T_
|
||||
func getInstanceFunc2<T: Foo>(t: T) -> (T) -> () -> () {
|
||||
// CHECK: [[REF:%.*]] = function_ref @_TFP21partial_apply_generic3Foo12instanceFuncuRq_S0__Fq_FT_T_
|
||||
// CHECK-NEXT: partial_apply [[REF]]<T>(
|
||||
return T.instanceFunc
|
||||
// CHECK-NEXT: destroy_addr %0 : $*
|
||||
// CHECK-NEXT: return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden @_TF21partial_apply_generic16getInstanceFunc3uRq_S_3Foo_FMq_Fq_FT_T_
|
||||
func getInstanceFunc3<T: Foo>(t: T.Type) -> (T) -> () -> () {
|
||||
// CHECK: [[REF:%.*]] = function_ref @_TFP21partial_apply_generic3Foo12instanceFuncuRq_S0__Fq_FT_T_
|
||||
// CHECK-NEXT: partial_apply [[REF]]<T>(
|
||||
return t.instanceFunc
|
||||
// CHECK-NEXT: return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil shared @_TZFP21partial_apply_generic3Foo3foouRq_S0__FMq_FT_T_
|
||||
// CHECK: witness_method $Self, #Foo.foo!1
|
||||
|
||||
@@ -6,3 +6,12 @@ func foo(inout x: Int) {
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
// But not partially applied.
|
||||
func curriedFoo(inout x: Int)(y: Int) -> Int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
var score: Int = 0
|
||||
|
||||
_ = curriedFoo(&score) // expected-error {{partial application of function with 'inout' parameters is not allowed}}
|
||||
|
||||
Reference in New Issue
Block a user