Skip to content

Commit 56d0399

Browse files
authored
Merge pull request #60240 from hamishknight/functional-filter
[CS] Filter out uncallable vars when simplifying applied overloads
2 parents 1845414 + 5418e8d commit 56d0399

File tree

12 files changed

+84
-77
lines changed

12 files changed

+84
-77
lines changed

include/swift/AST/ArgumentList.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -527,13 +527,6 @@ class alignas(Argument) ArgumentList final
527527
ASTContext &ctx,
528528
llvm::function_ref<Type(Expr *)> getType = __Expr_getType) const;
529529

530-
/// Avoid adding new usages of this. Creates a TupleType or ParenType
531-
/// representing the types in the argument list. A ParenType will be returned
532-
/// for a single argument, otherwise a TupleType.
533-
Type composeTupleOrParenType(
534-
ASTContext &ctx,
535-
llvm::function_ref<Type(Expr *)> getType = __Expr_getType) const;
536-
537530
/// Whether the argument list matches a given parameter list. This will return
538531
/// \c false if the arity doesn't match, or any of the canonical types or
539532
/// labels don't match. Note that this expects types to be present for the

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,6 @@ ERROR(cannot_pass_rvalue_inout,none,
256256
ERROR(cannot_provide_default_value_inout,none,
257257
"cannot provide default value to inout parameter %0", (Identifier))
258258

259-
ERROR(cannot_call_with_params, none,
260-
"cannot invoke %select{|initializer for type }2'%0' with an argument list"
261-
" of type '%1'", (StringRef, StringRef, bool))
262-
263259
ERROR(cannot_call_non_function_value,none,
264260
"cannot call value of non-function type %0", (Type))
265261

include/swift/AST/Types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,11 @@ class alignas(1 << TypeAlignInBits) TypeBase
918918
getAnyNominal());
919919
}
920920

921+
/// Checks whether this type may potentially be callable. This returns true
922+
/// for function types, metatypes, nominal types that support being called,
923+
/// and types that have not been inferred yet.
924+
bool mayBeCallable(DeclContext *dc);
925+
921926
/// Checks whether this is a type that supports being called through the
922927
/// implementation of a \c callAsFunction method. Note that this does not
923928
/// check access control.

lib/AST/ArgumentList.cpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -262,32 +262,6 @@ Expr *ArgumentList::packIntoImplicitTupleOrParen(
262262
return tuple;
263263
}
264264

265-
Type ArgumentList::composeTupleOrParenType(
266-
ASTContext &ctx, llvm::function_ref<Type(Expr *)> getType) const {
267-
if (auto *unary = getUnlabeledUnaryExpr()) {
268-
auto ty = getType(unary);
269-
assert(ty);
270-
ParameterTypeFlags flags;
271-
if (get(0).isInOut()) {
272-
ty = ty->getInOutObjectType();
273-
flags = flags.withInOut(true);
274-
}
275-
return ParenType::get(ctx, ty, flags);
276-
}
277-
SmallVector<TupleTypeElt, 4> elts;
278-
for (auto arg : *this) {
279-
auto ty = getType(arg.getExpr());
280-
assert(ty);
281-
ParameterTypeFlags flags;
282-
if (arg.isInOut()) {
283-
ty = ty->getInOutObjectType();
284-
flags = flags.withInOut(true);
285-
}
286-
elts.emplace_back(ty, arg.getLabel(), flags);
287-
}
288-
return TupleType::get(elts, ctx);
289-
}
290-
291265
bool ArgumentList::matches(ArrayRef<AnyFunctionType::Param> params,
292266
llvm::function_ref<Type(Expr *)> getType) const {
293267
if (size() != params.size())

lib/AST/Type.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,6 +1992,26 @@ const llvm::fltSemantics &BuiltinFloatType::getAPFloatSemantics() const {
19921992
llvm::report_fatal_error("Unknown FP semantics");
19931993
}
19941994

1995+
bool TypeBase::mayBeCallable(DeclContext *dc) {
1996+
if (is<AnyFunctionType>())
1997+
return true;
1998+
1999+
// Callable for construction.
2000+
if (is<AnyMetatypeType>())
2001+
return true;
2002+
2003+
// Unresolved types that could potentially be callable.
2004+
if (isPlaceholder() || is<UnresolvedType>() ||
2005+
isTypeParameter() || isTypeVariableOrMember()) {
2006+
return true;
2007+
}
2008+
// Callable nominal types.
2009+
if (isCallAsFunctionType(dc) || hasDynamicCallableAttribute())
2010+
return true;
2011+
2012+
return false;
2013+
}
2014+
19952015
bool TypeBase::mayHaveSuperclass() {
19962016
if (getClassOrBoundGenericClass())
19972017
return true;

lib/Sema/CSApply.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7747,9 +7747,14 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
77477747
callee = resolveConcreteDeclRef(decl, calleeLoc);
77487748
}
77497749

7750+
// Make sure we have a function type that is callable. This helps ensure
7751+
// Type::mayBeCallable stays up-to-date.
7752+
auto fnRValueTy = cs.getType(fn)->getRValueType();
7753+
assert(fnRValueTy->mayBeCallable(dc));
7754+
77507755
// If this is an implicit call to a `callAsFunction` method, build the
77517756
// appropriate member reference.
7752-
if (cs.getType(fn)->getRValueType()->isCallAsFunctionType(dc)) {
7757+
if (fnRValueTy->isCallAsFunctionType(dc)) {
77537758
fn = buildCallAsFunctionMethodRef(*this, apply, *overload, calleeLoc);
77547759
if (!fn)
77557760
return nullptr;

lib/Sema/CSDiagnostics.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6991,20 +6991,6 @@ bool ExtraneousCallFailure::diagnoseAsError() {
69916991
}
69926992
}
69936993

6994-
if (auto *UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
6995-
auto *baseExpr = UDE->getBase();
6996-
auto *call = castToExpr<CallExpr>(getRawAnchor());
6997-
6998-
if (getType(baseExpr)->isAnyObject()) {
6999-
auto argsTy = call->getArgs()->composeTupleOrParenType(
7000-
getASTContext(), [&](Expr *E) { return getType(E); });
7001-
emitDiagnostic(diag::cannot_call_with_params,
7002-
UDE->getName().getBaseName().userFacingName(),
7003-
argsTy.getString(), isa<TypeExpr>(baseExpr));
7004-
return true;
7005-
}
7006-
}
7007-
70086994
auto diagnostic =
70096995
emitDiagnostic(diag::cannot_call_non_function_value, getType(anchor));
70106996
removeParensFixIt(diagnostic);

lib/Sema/CSSimplify.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ bool constraints::doesMemberRefApplyCurriedSelf(Type baseTy,
135135
}
136136

137137
static bool areConservativelyCompatibleArgumentLabels(
138-
OverloadChoice choice, SmallVectorImpl<FunctionType::Param> &args,
138+
ConstraintSystem &cs, OverloadChoice choice,
139+
SmallVectorImpl<FunctionType::Param> &args,
139140
MatchCallArgumentListener &listener,
140141
Optional<unsigned> unlabeledTrailingClosureArgIndex) {
141142
ValueDecl *decl = nullptr;
@@ -155,23 +156,35 @@ static bool areConservativelyCompatibleArgumentLabels(
155156
return true;
156157
}
157158

158-
if (!decl->hasParameterList())
159-
return true;
160-
161-
// This is a member lookup, which generally means that the call arguments
162-
// (if we have any) will apply to the second level of parameters, with
163-
// the member lookup applying the curried self at the first level. But there
164-
// are cases where we can get an unapplied declaration reference back.
159+
// If this is a member lookup, the call arguments (if we have any) will
160+
// generally be applied to the second level of parameters, with the member
161+
// lookup applying the curried self at the first level. But there are cases
162+
// where we can get an unapplied declaration reference back.
165163
auto hasAppliedSelf =
166164
decl->hasCurriedSelf() &&
167165
doesMemberRefApplyCurriedSelf(choice.getBaseType(), decl);
168166

169-
auto *fnType = decl->getInterfaceType()->castTo<AnyFunctionType>();
170-
if (hasAppliedSelf) {
171-
fnType = fnType->getResult()->getAs<AnyFunctionType>();
172-
assert(fnType && "Parameter list curry level does not match type");
167+
AnyFunctionType *fnType = nullptr;
168+
if (decl->hasParameterList()) {
169+
fnType = decl->getInterfaceType()->castTo<AnyFunctionType>();
170+
if (hasAppliedSelf) {
171+
fnType = fnType->getResult()->getAs<AnyFunctionType>();
172+
assert(fnType && "Parameter list curry level does not match type");
173+
}
174+
} else if (auto *VD = dyn_cast<VarDecl>(decl)) {
175+
// For variables, we can reject any type that we know cannot be callable.
176+
auto varTy = VD->getValueInterfaceType()->lookThroughAllOptionalTypes();
177+
if (!varTy->mayBeCallable(cs.DC))
178+
return false;
179+
fnType = varTy->getAs<AnyFunctionType>();
173180
}
174181

182+
// Given we want to be conservative with this checking, if there's any case
183+
// we can't match arguments for (e.g callable nominals, type parameters),
184+
// default to returning true.
185+
if (!fnType)
186+
return true;
187+
175188
auto params = fnType->getParams();
176189
ParameterListInfo paramInfo(params, decl, hasAppliedSelf);
177190

@@ -11014,7 +11027,7 @@ bool ConstraintSystem::simplifyAppliedOverloadsImpl(
1101411027

1101511028
auto labelsMatch = [&](MatchCallArgumentListener &listener) {
1101611029
if (areConservativelyCompatibleArgumentLabels(
11017-
choice, argsWithLabels, listener,
11030+
*this, choice, argsWithLabels, listener,
1101811031
argList->getFirstTrailingClosureIndex()))
1101911032
return true;
1102011033

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4403,19 +4403,17 @@ static bool diagnoseAmbiguity(
44034403
type->lookThroughAllOptionalTypes()->getAs<AnyFunctionType>();
44044404
assert(fn);
44054405

4406-
if (fn->getNumParams() == 1) {
4407-
auto *argList =
4408-
solution.getArgumentList(solution.Fixes.front()->getLocator());
4409-
assert(argList);
4406+
auto *argList =
4407+
solution.getArgumentList(solution.Fixes.front()->getLocator());
4408+
assert(argList);
44104409

4410+
if (fn->getNumParams() == 1 && argList->isUnary()) {
44114411
const auto &param = fn->getParams()[0];
4412-
auto argType = argList->composeTupleOrParenType(
4413-
cs.getASTContext(),
4414-
[&](Expr *E) { return solution.getResolvedType(E); });
4412+
auto argTy = solution.getResolvedType(argList->getUnaryExpr());
44154413

44164414
DE.diagnose(noteLoc, diag::candidate_has_invalid_argument_at_position,
44174415
solution.simplifyType(param.getPlainType()),
4418-
/*position=*/1, param.isInOut(), argType);
4416+
/*position=*/1, param.isInOut(), argTy);
44194417
} else {
44204418
DE.diagnose(noteLoc, diag::candidate_partial_match,
44214419
fn->getParamListAsString(fn->getParams()));

test/ClangImporter/objc_parse.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ class IncompleteProtocolAdopter : Incomplete, IncompleteOptional { // expected-e
506506

507507
func testNullarySelectorPieces(_ obj: AnyObject) {
508508
obj.foo(1, bar: 2, 3) // no-warning
509-
obj.foo(1, 2, bar: 3) // expected-error{{cannot invoke 'foo' with an argument list of type '(Int, Int, bar: Int)'}}
509+
obj.foo(1, 2, bar: 3) // expected-error{{argument 'bar' must precede unnamed argument #2}}
510510
}
511511

512512
func testFactoryMethodAvailability() {

test/Constraints/diagnostics.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,9 +1303,14 @@ func f11(_ n: Int) {}
13031303
func f11<T : P2>(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{where 'T' = 'Int'}}
13041304
f11(3, f4) // expected-error {{global function 'f11' requires that 'Int' conform to 'P2'}}
13051305

1306-
let f12: (Int) -> Void = { _ in } // expected-note {{candidate '(Int) -> Void' requires 1 argument, but 2 were provided}}
1307-
func f12<T : P2>(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{candidate requires that 'Int' conform to 'P2' (requirement specified as 'T' : 'P2')}}
1308-
f12(3, f4)// expected-error {{no exact matches in call to global function 'f12'}}
1306+
let f12: (Int) -> Void = { _ in }
1307+
func f12<T : P2>(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{where 'T' = 'Int'}}
1308+
f12(3, f4)// expected-error {{global function 'f12' requires that 'Int' conform to 'P2'}}
1309+
1310+
// SR-15293: Bad diagnostic for var + func overload with mismatched call
1311+
func f13(x: Int, y: Int) {}
1312+
var f13: Any = 0
1313+
f13(0, x: 0) // expected-error {{incorrect argument labels in call (have '_:x:', expected 'x:y:')}}
13091314

13101315
// SR-12242
13111316
struct SR_12242_R<Value> {}

test/Constraints/generics.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,3 +965,15 @@ do {
965965
let g2: Gift<Sweets> = Gift<Chocolate>(box)
966966
// expected-error@-1 {{cannot assign value of type 'Gift<Chocolate>' to type 'Gift<Sweets>'}}
967967
}
968+
969+
func testOverloadGenericVarFn() {
970+
struct S<T> {
971+
var foo: T
972+
func foo(_ y: Int) {}
973+
init() { fatalError() }
974+
}
975+
// Make sure we can pick the variable overload over the function.
976+
S<(String) -> Void>().foo("")
977+
S<((String) -> Void)?>().foo?("")
978+
S<((String) -> Void)?>().foo!("")
979+
}

0 commit comments

Comments
 (0)