Skip to content

Commit ceb36c7

Browse files
authored
Merge pull request #36740 from Jumhyn/placeholder-types
Placeholder types: take two
2 parents f737043 + c1ed499 commit ceb36c7

32 files changed

+808
-203
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3596,6 +3596,11 @@ ERROR(unresolved_nil_literal,none,
35963596
ERROR(cannot_force_unwrap_nil_literal,none,
35973597
"'nil' literal cannot be force unwrapped", ())
35983598

3599+
ERROR(could_not_infer_placeholder,none,
3600+
"could not infer type for placeholder", ())
3601+
ERROR(top_level_placeholder_type,none,
3602+
"placeholders are not allowed as top-level types", ())
3603+
35993604
ERROR(type_of_expression_is_ambiguous,none,
36003605
"type of expression is ambiguous without more context", ())
36013606

@@ -3673,7 +3678,7 @@ NOTE(descriptive_generic_type_declared_here,none,
36733678
"%0 declared here", (StringRef))
36743679

36753680
ERROR(placeholder_type_not_allowed,none,
3676-
"you cannot use a placeholder type here", ())
3681+
"type placeholder not allowed here", ())
36773682

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

include/swift/AST/Expr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,9 @@ class alignas(8) Expr {
558558
/// the parent map.
559559
llvm::DenseMap<Expr *, Expr *> getParentMap();
560560

561+
/// Whether this expression is a valid parent for a TypeExpr.
562+
bool isValidTypeExprParent() const;
563+
561564
SWIFT_DEBUG_DUMP;
562565
void dump(raw_ostream &OS, unsigned Indent = 0) const;
563566
void dump(raw_ostream &OS, llvm::function_ref<Type(Expr *)> getType,

include/swift/Sema/CSFix.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ enum class FixKind : uint8_t {
328328
/// another property wrapper that is a part of the same composed
329329
/// property wrapper.
330330
AllowWrappedValueMismatch,
331+
332+
/// Specify a type for an explicitly written placeholder that could not be
333+
/// resolved.
334+
SpecifyTypeForPlaceholder
331335
};
332336

333337
class ConstraintFix {
@@ -2257,6 +2261,25 @@ class SpecifyContextualTypeForNil final : public ConstraintFix {
22572261
ConstraintLocator * locator);
22582262
};
22592263

2264+
class SpecifyTypeForPlaceholder final : public ConstraintFix {
2265+
SpecifyTypeForPlaceholder(ConstraintSystem &cs, ConstraintLocator *locator)
2266+
: ConstraintFix(cs, FixKind::SpecifyTypeForPlaceholder, locator) {}
2267+
2268+
public:
2269+
std::string getName() const override {
2270+
return "specify type for placeholder";
2271+
}
2272+
2273+
bool diagnose(const Solution &solution, bool asNote = false) const override;
2274+
2275+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
2276+
return diagnose(*commonFixes.front().first);
2277+
}
2278+
2279+
static SpecifyTypeForPlaceholder *create(ConstraintSystem &cs,
2280+
ConstraintLocator *locator);
2281+
};
2282+
22602283
class AllowRefToInvalidDecl final : public ConstraintFix {
22612284
AllowRefToInvalidDecl(ConstraintSystem &cs, ConstraintLocator *locator)
22622285
: ConstraintFix(cs, FixKind::AllowRefToInvalidDecl, locator) {}

lib/AST/Expr.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,130 @@ llvm::DenseMap<Expr *, Expr *> Expr::getParentMap() {
742742
return parentMap;
743743
}
744744

745+
bool Expr::isValidTypeExprParent() const {
746+
// Allow references to types as a part of:
747+
// - member references T.foo, T.Type, T.self, etc.
748+
// - constructor calls T()
749+
// - Subscripts T[]
750+
//
751+
// This is an exhaustive list of the accepted syntactic forms.
752+
switch (getKind()) {
753+
case ExprKind::Error:
754+
case ExprKind::DotSelf:
755+
case ExprKind::Call:
756+
case ExprKind::MemberRef:
757+
case ExprKind::UnresolvedMember:
758+
case ExprKind::DotSyntaxCall:
759+
case ExprKind::ConstructorRefCall:
760+
case ExprKind::UnresolvedDot:
761+
case ExprKind::DotSyntaxBaseIgnored:
762+
case ExprKind::UnresolvedSpecialize:
763+
case ExprKind::OpenExistential:
764+
case ExprKind::Subscript:
765+
return true;
766+
767+
case ExprKind::NilLiteral:
768+
case ExprKind::BooleanLiteral:
769+
case ExprKind::IntegerLiteral:
770+
case ExprKind::FloatLiteral:
771+
case ExprKind::StringLiteral:
772+
case ExprKind::MagicIdentifierLiteral:
773+
case ExprKind::InterpolatedStringLiteral:
774+
case ExprKind::ObjectLiteral:
775+
case ExprKind::DiscardAssignment:
776+
case ExprKind::DeclRef:
777+
case ExprKind::SuperRef:
778+
case ExprKind::Type:
779+
case ExprKind::OtherConstructorDeclRef:
780+
case ExprKind::OverloadedDeclRef:
781+
case ExprKind::UnresolvedDeclRef:
782+
case ExprKind::DynamicMemberRef:
783+
case ExprKind::DynamicSubscript:
784+
case ExprKind::Sequence:
785+
case ExprKind::Paren:
786+
case ExprKind::Await:
787+
case ExprKind::UnresolvedMemberChainResult:
788+
case ExprKind::Try:
789+
case ExprKind::ForceTry:
790+
case ExprKind::OptionalTry:
791+
case ExprKind::Tuple:
792+
case ExprKind::Array:
793+
case ExprKind::Dictionary:
794+
case ExprKind::KeyPathApplication:
795+
case ExprKind::TupleElement:
796+
case ExprKind::CaptureList:
797+
case ExprKind::Closure:
798+
case ExprKind::AutoClosure:
799+
case ExprKind::InOut:
800+
case ExprKind::VarargExpansion:
801+
case ExprKind::DynamicType:
802+
case ExprKind::RebindSelfInConstructor:
803+
case ExprKind::OpaqueValue:
804+
case ExprKind::PropertyWrapperValuePlaceholder:
805+
case ExprKind::AppliedPropertyWrapper:
806+
case ExprKind::DefaultArgument:
807+
case ExprKind::BindOptional:
808+
case ExprKind::OptionalEvaluation:
809+
case ExprKind::ForceValue:
810+
case ExprKind::MakeTemporarilyEscapable:
811+
case ExprKind::PrefixUnary:
812+
case ExprKind::PostfixUnary:
813+
case ExprKind::Binary:
814+
case ExprKind::Load:
815+
case ExprKind::DestructureTuple:
816+
case ExprKind::UnresolvedTypeConversion:
817+
case ExprKind::FunctionConversion:
818+
case ExprKind::CovariantFunctionConversion:
819+
case ExprKind::CovariantReturnConversion:
820+
case ExprKind::ImplicitlyUnwrappedFunctionConversion:
821+
case ExprKind::MetatypeConversion:
822+
case ExprKind::CollectionUpcastConversion:
823+
case ExprKind::Erasure:
824+
case ExprKind::AnyHashableErasure:
825+
case ExprKind::BridgeToObjC:
826+
case ExprKind::BridgeFromObjC:
827+
case ExprKind::ConditionalBridgeFromObjC:
828+
case ExprKind::DerivedToBase:
829+
case ExprKind::ArchetypeToSuper:
830+
case ExprKind::InjectIntoOptional:
831+
case ExprKind::ClassMetatypeToObject:
832+
case ExprKind::ExistentialMetatypeToObject:
833+
case ExprKind::ProtocolMetatypeToObject:
834+
case ExprKind::InOutToPointer:
835+
case ExprKind::ArrayToPointer:
836+
case ExprKind::StringToPointer:
837+
case ExprKind::PointerToPointer:
838+
case ExprKind::ForeignObjectConversion:
839+
case ExprKind::UnevaluatedInstance:
840+
case ExprKind::UnderlyingToOpaque:
841+
case ExprKind::DifferentiableFunction:
842+
case ExprKind::LinearFunction:
843+
case ExprKind::DifferentiableFunctionExtractOriginal:
844+
case ExprKind::LinearFunctionExtractOriginal:
845+
case ExprKind::LinearToDifferentiableFunction:
846+
case ExprKind::ForcedCheckedCast:
847+
case ExprKind::ConditionalCheckedCast:
848+
case ExprKind::Is:
849+
case ExprKind::Coerce:
850+
case ExprKind::Arrow:
851+
case ExprKind::If:
852+
case ExprKind::EnumIsCase:
853+
case ExprKind::Assign:
854+
case ExprKind::CodeCompletion:
855+
case ExprKind::UnresolvedPattern:
856+
case ExprKind::LazyInitializer:
857+
case ExprKind::EditorPlaceholder:
858+
case ExprKind::ObjCSelector:
859+
case ExprKind::KeyPath:
860+
case ExprKind::KeyPathDot:
861+
case ExprKind::OneWay:
862+
case ExprKind::Tap:
863+
return false;
864+
}
865+
866+
llvm_unreachable("Unhandled ExprKind in switch.");
867+
}
868+
745869
//===----------------------------------------------------------------------===//
746870
// Support methods for Exprs.
747871
//===----------------------------------------------------------------------===//

lib/AST/TypeCheckRequests.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,6 @@ void InterfaceTypeRequest::cacheResult(Type type) const {
957957
auto *decl = std::get<0>(getStorage());
958958
if (type) {
959959
assert(!type->hasTypeVariable() && "Type variable in interface type");
960-
assert(!type->hasPlaceholder() && "Type placeholder in interface type");
961960
assert(!type->is<InOutType>() && "Interface type must be materializable");
962961
assert(!type->hasArchetype() && "Archetype in interface type");
963962
}

lib/Parse/ParsePattern.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,6 @@ static ParserStatus parseDefaultArgument(
152152
/// Determine whether we are at the start of a parameter name when
153153
/// parsing a parameter.
154154
bool Parser::startsParameterName(bool isClosure) {
155-
// '_' cannot be a type, so it must be a parameter name.
156-
if (Tok.is(tok::kw__))
157-
return true;
158-
159155
// To have a parameter name here, we need a name.
160156
if (!Tok.canBeArgumentLabel())
161157
return false;

lib/Parse/ParseType.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ LayoutConstraint Parser::parseLayoutConstraint(Identifier LayoutConstraintID) {
157157
/// type-simple '!'
158158
/// type-collection
159159
/// type-array
160+
/// '_'
160161
ParserResult<TypeRepr> Parser::parseTypeSimple(
161162
Diag<> MessageID, ParseTypeReason reason) {
162163
ParserResult<TypeRepr> ty;
@@ -189,6 +190,9 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
189190
ty = parseTypeCollection();
190191
break;
191192
}
193+
case tok::kw__:
194+
ty = makeParserResult(new (Context) PlaceholderTypeRepr(consumeToken()));
195+
break;
192196
case tok::kw_protocol:
193197
if (startsWithLess(peekToken())) {
194198
ty = parseOldStyleProtocolComposition();
@@ -1469,6 +1473,9 @@ bool Parser::canParseType() {
14691473
if (!consumeIf(tok::r_square))
14701474
return false;
14711475
break;
1476+
case tok::kw__:
1477+
consumeToken();
1478+
break;
14721479

14731480

14741481
default:

lib/Sema/CSApply.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6644,6 +6644,19 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
66446644
Optional<Pattern*> typeFromPattern) {
66456645
auto &ctx = cs.getASTContext();
66466646

6647+
// Diagnose conversions to invalid function types that couldn't be performed
6648+
// beforehand because of placeholders.
6649+
if (auto *fnTy = toType->getAs<FunctionType>()) {
6650+
auto contextTy = cs.getContextualType(expr);
6651+
if (cs.getConstraintLocator(locator)->isForContextualType() && contextTy &&
6652+
contextTy->hasPlaceholder()) {
6653+
bool hadError = TypeChecker::diagnoseInvalidFunctionType(
6654+
fnTy, expr->getLoc(), None, dc, None);
6655+
if (hadError)
6656+
return nullptr;
6657+
}
6658+
}
6659+
66476660
// The type we're converting from.
66486661
Type fromType = cs.getType(expr);
66496662

lib/Sema/CSBindings.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,11 @@ TypeVariableBinding::fixForHole(ConstraintSystem &cs) const {
19041904
return std::make_pair(fix, defaultImpact);
19051905
}
19061906

1907+
if (srcLocator->isLastElement<LocatorPathElt::PlaceholderType>()) {
1908+
ConstraintFix *fix = SpecifyTypeForPlaceholder::create(cs, srcLocator);
1909+
return std::make_pair(fix, defaultImpact);
1910+
}
1911+
19071912
if (dstLocator->directlyAt<NilLiteralExpr>()) {
19081913
// This is a dramatic event, it means that there is absolutely
19091914
// no contextual information to resolve type of `nil`.

lib/Sema/CSDiagnostics.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7501,6 +7501,19 @@ bool MissingContextualTypeForNil::diagnoseAsError() {
75017501
return true;
75027502
}
75037503

7504+
bool CouldNotInferPlaceholderType::diagnoseAsError() {
7505+
// If this placeholder was explicitly written out by the user, they can maybe
7506+
// fix things by specifying an actual type.
7507+
if (auto *typeExpr = getAsExpr<TypeExpr>(getAnchor())) {
7508+
if (typeExpr->getLoc().isValid()) {
7509+
emitDiagnostic(diag::could_not_infer_placeholder);
7510+
return true;
7511+
}
7512+
}
7513+
7514+
return false;
7515+
}
7516+
75047517
bool ReferenceToInvalidDeclaration::diagnoseAsError() {
75057518
auto &DE = getASTContext().Diags;
75067519

lib/Sema/CSDiagnostics.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2406,6 +2406,21 @@ class MissingContextualTypeForNil final : public FailureDiagnostic {
24062406
bool diagnoseAsError() override;
24072407
};
24082408

2409+
/// Diagnose situations where there is no context to determine the type of a
2410+
/// placeholder, e.g.,
2411+
///
2412+
/// \code
2413+
/// let _ = _.foo
2414+
/// \endcode
2415+
class CouldNotInferPlaceholderType final : public FailureDiagnostic {
2416+
public:
2417+
CouldNotInferPlaceholderType(const Solution &solution,
2418+
ConstraintLocator *locator)
2419+
: FailureDiagnostic(solution, locator) {}
2420+
2421+
bool diagnoseAsError() override;
2422+
};
2423+
24092424
/// Diagnostic situations where AST node references an invalid declaration.
24102425
///
24112426
/// \code

lib/Sema/CSFix.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,18 @@ SpecifyContextualTypeForNil::create(ConstraintSystem &cs,
17501750
return new (cs.getAllocator()) SpecifyContextualTypeForNil(cs, locator);
17511751
}
17521752

1753+
bool SpecifyTypeForPlaceholder::diagnose(const Solution &solution,
1754+
bool asNote) const {
1755+
CouldNotInferPlaceholderType failure(solution, getLocator());
1756+
return failure.diagnose(asNote);
1757+
}
1758+
1759+
SpecifyTypeForPlaceholder *
1760+
SpecifyTypeForPlaceholder::create(ConstraintSystem &cs,
1761+
ConstraintLocator *locator) {
1762+
return new (cs.getAllocator()) SpecifyTypeForPlaceholder(cs, locator);
1763+
}
1764+
17531765
bool AllowRefToInvalidDecl::diagnose(const Solution &solution,
17541766
bool asNote) const {
17551767
ReferenceToInvalidDeclaration failure(solution, getLocator());

lib/Sema/CSGen.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2079,7 +2079,9 @@ namespace {
20792079
extInfo = extInfo.withGlobalActor(getExplicitGlobalActor(closure));
20802080
}
20812081

2082-
return FunctionType::get(closureParams, resultTy, extInfo);
2082+
auto *fnTy = FunctionType::get(closureParams, resultTy, extInfo);
2083+
return CS.replaceInferableTypesWithTypeVars(
2084+
fnTy, CS.getConstraintLocator(closure))->castTo<FunctionType>();
20832085
}
20842086

20852087
/// Produces a type for the given pattern, filling in any missing

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11484,7 +11484,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1148411484
case FixKind::AllowAlwaysSucceedCheckedCast:
1148511485
case FixKind::AllowInvalidStaticMemberRefOnProtocolMetatype:
1148611486
case FixKind::AllowWrappedValueMismatch:
11487-
case FixKind::RemoveExtraneousArguments: {
11487+
case FixKind::RemoveExtraneousArguments:
11488+
case FixKind::SpecifyTypeForPlaceholder: {
1148811489
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1148911490
}
1149011491

lib/Sema/MiscDiagnostics.cpp

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -620,25 +620,9 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
620620
// literal since it used to be accepted.
621621
DiagnosticBehavior behavior = DiagnosticBehavior::Error;
622622

623-
// Allow references to types as a part of:
624-
// - member references T.foo, T.Type, T.self, etc.
625-
// - constructor calls T()
626-
// - Subscripts T[]
627623
if (auto *ParentExpr = Parent.getAsExpr()) {
628-
// This is an exhaustive list of the accepted syntactic forms.
629-
if (isa<ErrorExpr>(ParentExpr) ||
630-
isa<DotSelfExpr>(ParentExpr) || // T.self
631-
isa<CallExpr>(ParentExpr) || // T()
632-
isa<MemberRefExpr>(ParentExpr) || // T.foo
633-
isa<UnresolvedMemberExpr>(ParentExpr) ||
634-
isa<SelfApplyExpr>(ParentExpr) || // T.foo() T()
635-
isa<UnresolvedDotExpr>(ParentExpr) ||
636-
isa<DotSyntaxBaseIgnoredExpr>(ParentExpr) ||
637-
isa<UnresolvedSpecializeExpr>(ParentExpr) ||
638-
isa<OpenExistentialExpr>(ParentExpr) ||
639-
isa<SubscriptExpr>(ParentExpr)) {
624+
if (ParentExpr->isValidTypeExprParent())
640625
return;
641-
}
642626

643627
if (!Ctx.LangOpts.isSwiftVersionAtLeast(6)) {
644628
auto argument = CallArgs.find(ParentExpr);

0 commit comments

Comments
 (0)