Skip to content

Commit ceb36c7

Browse files
authored
Merge pull request swiftlang#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

0 commit comments

Comments
 (0)