Skip to content

Commit c662a91

Browse files
authored
Merge pull request #29490 from xedin/remove-more-code-from-visitapplyexpr
[Diagnostics] Don't re-typecheck function expression associated with various calls
2 parents 2b5fa68 + e50756c commit c662a91

File tree

7 files changed

+47
-107
lines changed

7 files changed

+47
-107
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 5 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,32 +1202,6 @@ static Expr *getFailedArgumentExpr(CalleeCandidateInfo CCI, Expr *argExpr) {
12021202
bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI,
12031203
Expr *fnExpr, Expr *argExpr,
12041204
ArrayRef<Identifier> argLabels) {
1205-
if (auto *MTT = CS.getType(fnExpr)->getAs<MetatypeType>()) {
1206-
auto instTy = MTT->getInstanceType();
1207-
auto &DE = CS.getASTContext().Diags;
1208-
if (instTy->getAnyNominal()) {
1209-
// If we are invoking a constructor on a nominal type and there are
1210-
// absolutely no candidates, then they must all be private.
1211-
if (CCI.empty() || (CCI.size() == 1 && CCI.candidates[0].getDecl() &&
1212-
isa<ProtocolDecl>(CCI.candidates[0].getDecl()))) {
1213-
DE.diagnose(fnExpr->getLoc(), diag::no_accessible_initializers,
1214-
instTy);
1215-
return true;
1216-
}
1217-
// continue below
1218-
} else if (!instTy->is<TupleType>()) {
1219-
// If we are invoking a constructor on a non-nominal type, the expression
1220-
// is malformed.
1221-
SourceRange initExprRange(fnExpr->getSourceRange().Start,
1222-
argExpr->getSourceRange().End);
1223-
DE.diagnose(fnExpr->getLoc(), instTy->isExistentialType() ?
1224-
diag::construct_protocol_by_name :
1225-
diag::non_nominal_no_initializers, instTy)
1226-
.highlight(initExprRange);
1227-
return true;
1228-
}
1229-
}
1230-
12311205
// Try to diagnose errors related to the use of implicit self reference.
12321206
if (diagnoseImplicitSelfErrors(fnExpr, argExpr, CCI, argLabels))
12331207
return true;
@@ -1268,59 +1242,9 @@ bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI,
12681242
return false;
12691243
}
12701244

1271-
// Check if there is a structural problem in the function expression
1272-
// by performing type checking with the option to allow unresolved
1273-
// type variables. If that is going to produce a function type with
1274-
// unresolved result let's not re-typecheck the function expression,
1275-
// because it might produce unrelated diagnostics due to lack of
1276-
// contextual information.
1277-
static bool shouldTypeCheckFunctionExpr(FailureDiagnosis &FD, DeclContext *DC,
1278-
Expr *fnExpr) {
1279-
if (!isa<UnresolvedDotExpr>(fnExpr))
1280-
return true;
1281-
1282-
SmallPtrSet<TypeBase *, 4> fnTypes;
1283-
FD.getPossibleTypesOfExpressionWithoutApplying(
1284-
fnExpr, DC, fnTypes, FreeTypeVariableBinding::UnresolvedType);
1285-
1286-
if (fnTypes.size() == 1) {
1287-
// Some member types depend on the arguments to produce a result type,
1288-
// type-checking such expressions without associated arguments is
1289-
// going to produce unrelated diagnostics.
1290-
if (auto fn = (*fnTypes.begin())->getAs<AnyFunctionType>()) {
1291-
auto resultType = fn->getResult();
1292-
if (resultType->hasUnresolvedType() || resultType->hasTypeVariable())
1293-
return false;
1294-
}
1295-
}
1296-
1297-
// Might be a structural problem related to the member itself.
1298-
return true;
1299-
}
1300-
13011245
bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
13021246
auto *fnExpr = callExpr->getFn();
1303-
1304-
if (shouldTypeCheckFunctionExpr(*this, CS.DC, fnExpr)) {
1305-
// Type check the function subexpression to resolve a type for it if
1306-
// possible.
1307-
fnExpr = typeCheckChildIndependently(callExpr->getFn());
1308-
if (!fnExpr) {
1309-
return CS.getASTContext().Diags.hadAnyError();
1310-
}
1311-
}
1312-
1313-
SWIFT_DEFER {
1314-
if (!fnExpr) return;
1315-
1316-
// If it's a member operator reference, put the operator back.
1317-
if (auto operatorRef = fnExpr->getMemberOperatorRef())
1318-
callExpr->setFn(operatorRef);
1319-
};
1320-
1321-
auto getFuncType = [](Type type) -> Type { return type->getRValueType(); };
1322-
1323-
auto fnType = getFuncType(CS.getType(fnExpr));
1247+
auto fnType = CS.getType(fnExpr)->getRValueType();
13241248

13251249
bool hasTrailingClosure = callArgHasTrailingClosure(callExpr->getArg());
13261250

@@ -1489,24 +1413,17 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
14891413
if (CS.getType(argExpr)->hasUnresolvedType())
14901414
return false;
14911415

1492-
SmallVector<AnyFunctionType::Param, 8> params;
1493-
AnyFunctionType::decomposeInput(CS.getType(argExpr), params);
1494-
auto argString = AnyFunctionType::getParamListAsString(params);
1495-
1496-
if (auto MTT = fnType->getAs<MetatypeType>()) {
1497-
if (MTT->getInstanceType()->isExistentialType()) {
1498-
diagnose(fnExpr->getLoc(), diag::construct_protocol_value, fnType);
1499-
return true;
1500-
}
1501-
}
1502-
15031416
bool isInitializer = isa<TypeExpr>(fnExpr);
15041417
if (isa<TupleExpr>(argExpr) &&
15051418
cast<TupleExpr>(argExpr)->getNumElements() == 0) {
15061419
// Emit diagnostics that say "no arguments".
15071420
diagnose(fnExpr->getLoc(), diag::cannot_call_with_no_params,
15081421
overloadName, isInitializer);
15091422
} else {
1423+
SmallVector<AnyFunctionType::Param, 8> params;
1424+
AnyFunctionType::decomposeInput(CS.getType(argExpr), params);
1425+
auto argString = AnyFunctionType::getParamListAsString(params);
1426+
15101427
diagnose(fnExpr->getLoc(), diag::cannot_call_with_params,
15111428
overloadName, argString, isInitializer);
15121429
}

lib/Sema/CSSimplify.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,8 +2249,17 @@ ConstraintSystem::matchTypesBindTypeVar(
22492249
// Simplify the right-hand type and perform the "occurs" check.
22502250
typeVar = getRepresentative(typeVar);
22512251
type = simplifyType(type, flags);
2252-
if (!isBindable(typeVar, type))
2252+
if (!isBindable(typeVar, type)) {
2253+
if (shouldAttemptFixes()) {
2254+
// If type variable is allowed to be a hole and it can't be bound to
2255+
// a particular (full resolved) type, just ignore this binding
2256+
// instead of re-trying it and failing later.
2257+
if (typeVar->getImpl().canBindToHole() && !type->hasTypeVariable())
2258+
return getTypeMatchSuccess();
2259+
}
2260+
22532261
return formUnsolvedResult();
2262+
}
22542263

22552264
// Since member lookup doesn't check requirements
22562265
// it might sometimes return types which are not
@@ -7509,6 +7518,18 @@ ConstraintSystem::simplifyApplicableFnConstraint(
75097518
// following: $T1 -> $T2.
75107519
auto func1 = type1->castTo<FunctionType>();
75117520

7521+
// If a type variable representing "function type" is a hole
7522+
// or it could be bound to some concrete type with a help of
7523+
// a fix, let's propagate holes to the "input" type. Doing so
7524+
// provides more information to upcoming argument and result matching.
7525+
if (shouldAttemptFixes()) {
7526+
if (auto *typeVar = type2->getAs<TypeVariableType>()) {
7527+
auto *locator = typeVar->getImpl().getLocator();
7528+
if (typeVar->isHole() || hasFixFor(locator))
7529+
recordPotentialHole(func1);
7530+
}
7531+
}
7532+
75127533
// Before stripping lvalue-ness and optional types, save the original second
75137534
// type for handling `func callAsFunction` and `@dynamicCallable`
75147535
// applications. This supports the following cases:
@@ -7721,10 +7742,7 @@ ConstraintSystem::simplifyApplicableFnConstraint(
77217742

77227743
// If there are any type variables associated with arguments/result
77237744
// they have to be marked as "holes".
7724-
type1.visit([&](Type subType) {
7725-
if (auto *typeVar = subType->getAs<TypeVariableType>())
7726-
recordPotentialHole(typeVar);
7727-
});
7745+
recordPotentialHole(func1);
77287746

77297747
if (desugar2->isHole())
77307748
return SolutionKind::Solved;
@@ -7998,11 +8016,7 @@ ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint(
79988016
return SolutionKind::Error;
79998017

80008018
recordPotentialHole(tv);
8001-
8002-
Type(func1).visit([&](Type type) {
8003-
if (auto *typeVar = type->getAs<TypeVariableType>())
8004-
recordPotentialHole(typeVar);
8005-
});
8019+
recordPotentialHole(func1);
80068020

80078021
return SolutionKind::Solved;
80088022
}
@@ -8563,6 +8577,14 @@ void ConstraintSystem::recordPotentialHole(TypeVariableType *typeVar) {
85638577
typeVar->getImpl().enableCanBindToHole(getSavedBindings());
85648578
}
85658579

8580+
void ConstraintSystem::recordPotentialHole(FunctionType *fnType) {
8581+
assert(fnType);
8582+
Type(fnType).visit([&](Type type) {
8583+
if (auto *typeVar = type->getAs<TypeVariableType>())
8584+
recordPotentialHole(typeVar);
8585+
});
8586+
}
8587+
85668588
ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
85678589
ConstraintFix *fix, Type type1, Type type2, ConstraintKind matchKind,
85688590
TypeMatchOptions flags, ConstraintLocatorBuilder locator) {

lib/Sema/ConstraintSystem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,6 +2359,7 @@ class ConstraintSystem {
23592359
bool recordFix(ConstraintFix *fix, unsigned impact = 1);
23602360

23612361
void recordPotentialHole(TypeVariableType *typeVar);
2362+
void recordPotentialHole(FunctionType *fnType);
23622363

23632364
/// Determine whether constraint system already has a fix recorded
23642365
/// for a particular location.

test/Constraints/bridging.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ func rdar19831698() {
265265
var v71 = true + 1.0 // expected-error{{binary operator '+' cannot be applied to operands of type 'Bool' and 'Double'}}
266266
// expected-note@-1{{overloads for '+'}}
267267
var v72 = true + true // expected-error{{binary operator '+' cannot be applied to two 'Bool' operands}}
268-
var v73 = true + [] // expected-error@:13 {{cannot convert value of type 'Bool' to expected argument type 'Array<Bool>'}}
268+
var v73 = true + [] // expected-error@:18 {{binary operator '+' cannot be applied to operands of type 'Bool' and '[Any]'}}
269269
var v75 = true + "str" // expected-error@:13 {{cannot convert value of type 'Bool' to expected argument type 'String'}}
270270
}
271271

test/Constraints/members.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,17 +405,17 @@ func bar_32854314() -> Int {
405405
extension Array where Element == Int {
406406
func foo() {
407407
let _ = min(foo_32854314(), bar_32854314()) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}}
408-
// expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min()'}}
408+
// expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min(by:)'}}
409409
}
410410

411411
func foo(_ x: Int, _ y: Double) {
412412
let _ = min(x, y) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}}
413-
// expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min()'}}
413+
// expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min(by:)'}}
414414
}
415415

416416
func bar() {
417417
let _ = min(1.0, 2) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}}
418-
// expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min()'}}
418+
// expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min(by:)'}}
419419
}
420420
}
421421

test/expr/expressions.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -748,10 +748,8 @@ func invalidDictionaryLiteral() {
748748
}
749749

750750

751-
[4].joined(separator: [1]) // expected-error {{cannot convert value of type 'Int' to expected element type 'String'}}
752-
// expected-error@-1 {{cannot convert value of type '[Int]' to expected argument type 'String'}}
753-
[4].joined(separator: [[[1]]]) // expected-error {{cannot convert value of type 'Int' to expected element type 'String'}}
754-
// expected-error@-1 {{cannot convert value of type '[[[Int]]]' to expected argument type 'String'}}
751+
[4].joined(separator: [1]) // expected-error {{referencing instance method 'joined(separator:)' on 'Sequence' requires that 'Int' conform to 'Sequence'}}
752+
[4].joined(separator: [[[1]]]) // expected-error {{referencing instance method 'joined(separator:)' on 'Sequence' requires that 'Int' conform to 'Sequence'}}
755753

756754
//===----------------------------------------------------------------------===//
757755
// nil/metatype comparisons

test/type/protocol_composition.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ takesP1AndP2([Swift.AnyObject & P1 & P2]())
173173
takesP1AndP2([AnyObject & protocol_composition.P1 & P2]())
174174
takesP1AndP2([AnyObject & P1 & protocol_composition.P2]())
175175
takesP1AndP2([DoesNotExist & P1 & P2]()) // expected-error {{use of unresolved identifier 'DoesNotExist'}}
176-
takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{module 'Swift' has no member named 'DoesNotExist'}}
176+
// TODO(diagnostics): The problem here is that `&` is interpreted as a binary operator, we need to re-think
177+
// how "missing member" fix is implemented because currently it finds N solutions with multiple fixes.
178+
takesP1AndP2([Swift.DoesNotExist & P1 & P2]()) // expected-error {{cannot invoke '' with no arguments}}
177179

178180
typealias T08 = P1 & inout P2 // expected-error {{'inout' may only be used on parameters}}
179181
typealias T09 = P1 & __shared P2 // expected-error {{'__shared' may only be used on parameters}}

0 commit comments

Comments
 (0)