Skip to content

Commit 658de80

Browse files
authored
Merge pull request swiftlang#39627 from CodaFi/the-replacements
Suggest Replacement Types for Invalid Placeholders
2 parents 245745b + ffff354 commit 658de80

18 files changed

+277
-134
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3624,8 +3624,6 @@ ERROR(cannot_force_unwrap_nil_literal,none,
36243624

36253625
ERROR(could_not_infer_placeholder,none,
36263626
"could not infer type for placeholder", ())
3627-
ERROR(top_level_placeholder_type,none,
3628-
"placeholders are not allowed as top-level types", ())
36293627

36303628
ERROR(type_of_expression_is_ambiguous,none,
36313629
"type of expression is ambiguous without more context", ())
@@ -3705,6 +3703,12 @@ NOTE(descriptive_generic_type_declared_here,none,
37053703

37063704
ERROR(placeholder_type_not_allowed,none,
37073705
"type placeholder not allowed here", ())
3706+
ERROR(placeholder_type_not_allowed_in_return_type,none,
3707+
"type placeholder may not appear in function return type", ())
3708+
ERROR(placeholder_type_not_allowed_in_parameter,none,
3709+
"type placeholder may not appear in top-level parameter", ())
3710+
NOTE(replace_placeholder_with_inferred_type,none,
3711+
"replace the placeholder with the inferred type %0", (Type))
37083712

37093713
WARNING(use_of_void_pointer,none,
37103714
"Unsafe%0Pointer<Void> has been replaced by Unsafe%0RawPointer", (StringRef))

lib/AST/ASTContext.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3644,7 +3644,6 @@ GenericFunctionType *GenericFunctionType::get(GenericSignature sig,
36443644
Optional<ExtInfo> info) {
36453645
assert(sig && "no generic signature for generic function type?!");
36463646
assert(!result->hasTypeVariable());
3647-
assert(!result->hasPlaceholder());
36483647

36493648
llvm::FoldingSetNodeID id;
36503649
GenericFunctionType::Profile(id, sig, params, result, info);

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,14 +1073,14 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
10731073
TypeBase *tybase = type.getPointer();
10741074
switch (type->getKind()) {
10751075
case TypeKind::TypeVariable:
1076-
case TypeKind::Placeholder:
10771076
llvm_unreachable("mangling type variable");
10781077

10791078
case TypeKind::Module:
10801079
llvm_unreachable("Cannot mangle module type yet");
10811080

10821081
case TypeKind::Error:
10831082
case TypeKind::Unresolved:
1083+
case TypeKind::Placeholder:
10841084
appendOperator("Xe");
10851085
return;
10861086

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8643,6 +8643,7 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
86438643
Type convertType = target.getExprConversionType();
86448644
auto shouldCoerceToContextualType = [&]() {
86458645
return convertType &&
8646+
!convertType->hasPlaceholder() &&
86468647
!target.isOptionalSomePatternInit() &&
86478648
!(solution.getType(resultExpr)->isUninhabited() &&
86488649
cs.getContextualTypePurpose(target.getAsExpr())

lib/Sema/CSGen.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,11 @@ namespace {
13261326
if (result->hasError()) {
13271327
return Type();
13281328
}
1329+
// Diagnose top-level usages of placeholder types.
1330+
if (isa<TopLevelCodeDecl>(CS.DC) && isa<PlaceholderTypeRepr>(repr)) {
1331+
CS.getASTContext().Diags.diagnose(repr->getLoc(),
1332+
diag::placeholder_type_not_allowed);
1333+
}
13291334
return result;
13301335
}
13311336

lib/Sema/MiscDiagnostics.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2712,6 +2712,65 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
27122712
}
27132713
};
27142714

2715+
class ReturnTypePlaceholderReplacer : public ASTWalker {
2716+
FuncDecl *Implementation;
2717+
BraceStmt *Body;
2718+
SmallVector<Type, 4> Candidates;
2719+
2720+
bool HasInvalidReturn = false;
2721+
2722+
public:
2723+
ReturnTypePlaceholderReplacer(FuncDecl *Implementation, BraceStmt *Body)
2724+
: Implementation(Implementation), Body(Body) {}
2725+
2726+
void check() {
2727+
auto *resultRepr = Implementation->getResultTypeRepr();
2728+
if (!resultRepr) {
2729+
return;
2730+
}
2731+
2732+
Implementation->getASTContext()
2733+
.Diags
2734+
.diagnose(resultRepr->getLoc(),
2735+
diag::placeholder_type_not_allowed_in_return_type)
2736+
.highlight(resultRepr->getSourceRange());
2737+
2738+
Body->walk(*this);
2739+
2740+
// If given function has any invalid returns in the body
2741+
// let's not try to validate the types, since it wouldn't
2742+
// be accurate.
2743+
if (HasInvalidReturn)
2744+
return;
2745+
2746+
auto writtenType = Implementation->getResultInterfaceType();
2747+
llvm::SmallPtrSet<TypeBase *, 8> seenTypes;
2748+
for (auto candidate : Candidates) {
2749+
if (!seenTypes.insert(candidate.getPointer()).second) {
2750+
continue;
2751+
}
2752+
TypeChecker::notePlaceholderReplacementTypes(writtenType, candidate);
2753+
}
2754+
}
2755+
2756+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override { return {true, E}; }
2757+
2758+
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
2759+
if (auto *RS = dyn_cast<ReturnStmt>(S)) {
2760+
if (RS->hasResult()) {
2761+
auto resultTy = RS->getResult()->getType();
2762+
HasInvalidReturn |= resultTy.isNull() || resultTy->hasError();
2763+
Candidates.push_back(resultTy);
2764+
}
2765+
}
2766+
2767+
return {true, S};
2768+
}
2769+
2770+
// Don't descend into nested decls.
2771+
bool walkToDeclPre(Decl *D) override { return false; }
2772+
};
2773+
27152774
} // end anonymous namespace
27162775

27172776
// After we have scanned the entire region, diagnose variables that could be
@@ -3277,6 +3336,13 @@ void swift::performAbstractFuncDeclDiagnostics(AbstractFunctionDecl *AFD) {
32773336
OpaqueUnderlyingTypeChecker(AFD, opaqueResultTy, body).check();
32783337
}
32793338
}
3339+
} else if (auto *FD = dyn_cast<FuncDecl>(AFD)) {
3340+
auto resultIFaceTy = FD->getResultInterfaceType();
3341+
// If the result has a placeholder, we need to try to use the contextual
3342+
// type inferred in the body to replace it.
3343+
if (resultIFaceTy && resultIFaceTy->hasPlaceholder()) {
3344+
ReturnTypePlaceholderReplacer(FD, body).check();
3345+
}
32803346
}
32813347
}
32823348

lib/Sema/PreCheckExpr.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,9 +1506,7 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) {
15061506
},
15071507
// FIXME: Don't let placeholder types escape type resolution.
15081508
// For now, just return the placeholder type.
1509-
[](auto &ctx, auto *originator) {
1510-
return Type();
1511-
});
1509+
PlaceholderType::get);
15121510
const auto BaseTy = resolution.resolveType(InnerTypeRepr);
15131511

15141512
if (BaseTy->mayHaveMembers()) {
@@ -2061,9 +2059,7 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) {
20612059
},
20622060
// FIXME: Don't let placeholder types escape type resolution.
20632061
// For now, just return the placeholder type.
2064-
[](auto &ctx, auto *originator) {
2065-
return Type();
2066-
});
2062+
PlaceholderType::get);
20672063
const auto result = resolution.resolveType(typeExpr->getTypeRepr());
20682064
if (result->hasError())
20692065
return nullptr;

lib/Sema/TypeCheckDecl.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,8 +2213,9 @@ ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
22132213
const auto options =
22142214
TypeResolutionOptions(TypeResolverContext::FunctionResult);
22152215
auto *const dc = decl->getInnermostDeclContext();
2216-
return TypeResolution::forInterface(dc, options, /*unboundTyOpener*/ nullptr,
2217-
/*placeholderHandler*/ nullptr)
2216+
return TypeResolution::forInterface(dc, options,
2217+
/*unboundTyOpener*/ nullptr,
2218+
PlaceholderType::get)
22182219
.resolveType(resultTyRepr);
22192220
}
22202221

@@ -2298,7 +2299,6 @@ static Type validateParameterType(ParamDecl *decl) {
22982299

22992300
TypeResolutionOptions options(None);
23002301
OpenUnboundGenericTypeFn unboundTyOpener = nullptr;
2301-
HandlePlaceholderTypeReprFn placeholderHandler = nullptr;
23022302
if (isa<AbstractClosureExpr>(dc)) {
23032303
options = TypeResolutionOptions(TypeResolverContext::ClosureExpr);
23042304
options |= TypeResolutionFlags::AllowUnspecifiedTypes;
@@ -2309,9 +2309,6 @@ static Type validateParameterType(ParamDecl *decl) {
23092309
};
23102310
// FIXME: Don't let placeholder types escape type resolution.
23112311
// For now, just return the placeholder type.
2312-
placeholderHandler = [](auto &ctx, auto *originator) {
2313-
return Type();
2314-
};
23152312
} else if (isa<AbstractFunctionDecl>(dc)) {
23162313
options = TypeResolutionOptions(TypeResolverContext::AbstractFunctionDecl);
23172314
} else if (isa<SubscriptDecl>(dc)) {
@@ -2334,7 +2331,7 @@ static Type validateParameterType(ParamDecl *decl) {
23342331

23352332
const auto resolution =
23362333
TypeResolution::forInterface(dc, options, unboundTyOpener,
2337-
placeholderHandler);
2334+
PlaceholderType::get);
23382335
auto Ty = resolution.resolveType(decl->getTypeRepr());
23392336

23402337
if (Ty->hasError()) {
@@ -2950,9 +2947,7 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const {
29502947
},
29512948
// FIXME: Don't let placeholder types escape type resolution.
29522949
// For now, just return the placeholder type.
2953-
[](auto &ctx, auto *originator) {
2954-
return Type();
2955-
});
2950+
PlaceholderType::get);
29562951

29572952
const auto extendedType = resolution.resolveType(extendedRepr);
29582953

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@
1818

1919
#include "CodeSynthesis.h"
2020
#include "DerivedConformances.h"
21-
#include "TypeChecker.h"
21+
#include "MiscDiagnostics.h"
2222
#include "TypeCheckAccess.h"
23+
#include "TypeCheckAvailability.h"
2324
#include "TypeCheckConcurrency.h"
2425
#include "TypeCheckDecl.h"
25-
#include "TypeCheckAvailability.h"
2626
#include "TypeCheckObjC.h"
2727
#include "TypeCheckType.h"
28-
#include "MiscDiagnostics.h"
29-
#include "swift/AST/AccessNotes.h"
30-
#include "swift/AST/AccessScope.h"
28+
#include "TypeChecker.h"
3129
#include "swift/AST/ASTPrinter.h"
3230
#include "swift/AST/ASTVisitor.h"
3331
#include "swift/AST/ASTWalker.h"
32+
#include "swift/AST/AccessNotes.h"
33+
#include "swift/AST/AccessScope.h"
3434
#include "swift/AST/ExistentialLayout.h"
3535
#include "swift/AST/Expr.h"
3636
#include "swift/AST/ForeignErrorConvention.h"
@@ -42,15 +42,15 @@
4242
#include "swift/AST/PropertyWrappers.h"
4343
#include "swift/AST/ProtocolConformance.h"
4444
#include "swift/AST/SourceFile.h"
45+
#include "swift/AST/TypeCheckRequests.h"
46+
#include "swift/AST/TypeDifferenceVisitor.h"
4547
#include "swift/AST/TypeWalker.h"
48+
#include "swift/Basic/Defer.h"
4649
#include "swift/Basic/Statistic.h"
4750
#include "swift/Parse/Lexer.h"
4851
#include "swift/Parse/Parser.h"
4952
#include "swift/Serialization/SerializedModuleLoader.h"
5053
#include "swift/Strings.h"
51-
#include "swift/AST/NameLookupRequests.h"
52-
#include "swift/AST/TypeCheckRequests.h"
53-
#include "swift/Basic/Defer.h"
5454
#include "llvm/ADT/APFloat.h"
5555
#include "llvm/ADT/APInt.h"
5656
#include "llvm/ADT/APSInt.h"
@@ -967,11 +967,65 @@ static void checkInheritedDefaultValueRestrictions(ParamDecl *PD) {
967967
}
968968
}
969969

970+
void TypeChecker::notePlaceholderReplacementTypes(Type writtenType,
971+
Type inferredType) {
972+
assert(writtenType && inferredType &&
973+
"Must provide both written and inferred types");
974+
assert(writtenType->hasPlaceholder() && "Written type has no placeholder?");
975+
976+
class PlaceholderNotator
977+
: public CanTypeDifferenceVisitor<PlaceholderNotator> {
978+
public:
979+
bool visitDifferentComponentTypes(CanType t1, CanType t2) {
980+
// Never replace anything the user wrote with an error type.
981+
if (t2->hasError() || t2->hasUnresolvedType()) {
982+
return false;
983+
}
984+
985+
auto *placeholder = t1->getAs<PlaceholderType>();
986+
if (!placeholder) {
987+
return false;
988+
}
989+
990+
if (auto *origRepr =
991+
placeholder->getOriginator().dyn_cast<PlaceholderTypeRepr *>()) {
992+
t1->getASTContext()
993+
.Diags
994+
.diagnose(origRepr->getLoc(),
995+
diag::replace_placeholder_with_inferred_type, t2)
996+
.fixItReplace(origRepr->getSourceRange(), t2.getString());
997+
}
998+
return false;
999+
}
1000+
1001+
bool check(Type t1, Type t2) {
1002+
return !visit(t1->getCanonicalType(), t2->getCanonicalType());
1003+
};
1004+
};
1005+
1006+
PlaceholderNotator().check(writtenType, inferredType);
1007+
}
1008+
9701009
/// Check the default arguments that occur within this pattern.
9711010
static void checkDefaultArguments(ParameterList *params) {
9721011
// Force the default values in case they produce diagnostics.
973-
for (auto *param : *params)
974-
(void)param->getTypeCheckedDefaultExpr();
1012+
for (auto *param : *params) {
1013+
auto ifacety = param->getInterfaceType();
1014+
auto *expr = param->getTypeCheckedDefaultExpr();
1015+
if (!ifacety->hasPlaceholder()) {
1016+
continue;
1017+
}
1018+
1019+
// Placeholder types are banned for all parameter decls. We try to use the
1020+
// freshly-checked default expression's contextual type to suggest a
1021+
// reasonable type to insert.
1022+
param->diagnose(diag::placeholder_type_not_allowed_in_parameter)
1023+
.highlight(param->getSourceRange());
1024+
if (expr && !expr->getType()->hasError()) {
1025+
TypeChecker::notePlaceholderReplacementTypes(
1026+
ifacety, expr->getType()->mapTypeOutOfContext());
1027+
}
1028+
}
9751029
}
9761030

9771031
Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator,

lib/Sema/TypeCheckPattern.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,7 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
494494
},
495495
// FIXME: Don't let placeholder types escape type resolution.
496496
// For now, just return the placeholder type.
497-
[](auto &ctx, auto *originator) {
498-
return Type();
499-
});
497+
PlaceholderType::get);
500498
const auto ty = resolution.resolveType(repr);
501499
auto *enumDecl = dyn_cast_or_null<EnumDecl>(ty->getAnyNominal());
502500
if (!enumDecl)
@@ -618,9 +616,7 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
618616
},
619617
// FIXME: Don't let placeholder types escape type resolution.
620618
// For now, just return the placeholder type.
621-
[](auto &ctx, auto *originator) {
622-
return Type();
623-
})
619+
PlaceholderType::get)
624620
.resolveType(prefixRepr);
625621
auto *enumDecl = dyn_cast_or_null<EnumDecl>(enumTy->getAnyNominal());
626622
if (!enumDecl)
@@ -830,9 +826,7 @@ Type PatternTypeRequest::evaluate(Evaluator &evaluator,
830826
};
831827
// FIXME: Don't let placeholder types escape type resolution.
832828
// For now, just return the placeholder type.
833-
placeholderHandler = [](auto &ctx, auto *originator) {
834-
return Type();
835-
};
829+
placeholderHandler = PlaceholderType::get;
836830
}
837831
return validateTypedPattern(
838832
cast<TypedPattern>(P),
@@ -900,9 +894,7 @@ Type PatternTypeRequest::evaluate(Evaluator &evaluator,
900894
};
901895
// FIXME: Don't let placeholder types escape type resolution.
902896
// For now, just return the placeholder type.
903-
placeholderHandler = [](auto &ctx, auto *originator) {
904-
return Type();
905-
};
897+
placeholderHandler = PlaceholderType::get;
906898
}
907899
TypedPattern *TP = cast<TypedPattern>(somePat->getSubPattern());
908900
const auto type = validateTypedPattern(

0 commit comments

Comments
 (0)