Skip to content

Commit b5c1eef

Browse files
authored
Merge pull request #11781 from slavapestov/cleanup-inheritance-clause-parsing
Cleanup inheritance clause parsing
2 parents 89f97a2 + 1e3d88e commit b5c1eef

16 files changed

+109
-140
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -685,8 +685,6 @@ ERROR(expected_identifier_for_type,PointsToFirstBadToken,
685685
"expected identifier for type name", ())
686686
ERROR(expected_rangle_generic_arg_list,PointsToFirstBadToken,
687687
"expected '>' to complete generic argument list", ())
688-
ERROR(expected_ident_type_in_inheritance,none,
689-
"inheritance from non-named type %0", (TypeLoc))
690688

691689

692690
// Function types
@@ -747,8 +745,6 @@ ERROR(tuple_type_multiple_labels,none,
747745
// Protocol Types
748746
ERROR(expected_rangle_protocol,PointsToFirstBadToken,
749747
"expected '>' to complete protocol-constrained type", ())
750-
ERROR(disallowed_protocol_composition,PointsToFirstBadToken,
751-
"protocol-constrained type is neither allowed nor needed here", ())
752748

753749
WARNING(swift3_deprecated_protocol_composition,none,
754750
"'protocol<...>' composition syntax is deprecated; join the protocols using '&'", ())
@@ -1418,7 +1414,7 @@ ERROR(expected_generics_parameter_name,PointsToFirstBadToken,
14181414
ERROR(unexpected_class_constraint,none,
14191415
"'class' constraint can only appear on protocol declarations", ())
14201416
NOTE(suggest_anyobject,none,
1421-
"did you mean to constrain %0 with the 'AnyObject' protocol?", (Identifier))
1417+
"did you mean to write an 'AnyObject' constraint?", ())
14221418
ERROR(expected_generics_type_restriction,none,
14231419
"expected a class type or protocol-constrained type restricting %0",
14241420
(Identifier))
@@ -1427,8 +1423,6 @@ ERROR(requires_single_equal,none,
14271423
ERROR(expected_requirement_delim,none,
14281424
"expected ':' or '==' to indicate a conformance or same-type requirement",
14291425
())
1430-
ERROR(invalid_class_requirement,none,
1431-
"'class' requirement only applies to protocols", ())
14321426
ERROR(redundant_class_requirement,none,
14331427
"redundant 'class' requirement", ())
14341428
ERROR(late_class_requirement,none,

include/swift/Parse/Parser.h

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,8 @@ class Parser {
773773
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
774774
DeclAttributes &Attributes);
775775
ParserStatus parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
776-
bool allowClassRequirement);
776+
bool allowClassRequirement,
777+
bool allowAnyObject);
777778
ParserStatus parseDeclItem(bool &PreviousHadSemi,
778779
Parser::ParseDeclOptions Options,
779780
llvm::function_ref<void(Decl*)> handler);
@@ -881,20 +882,6 @@ class Parser {
881882
bool HandleCodeCompletion = true,
882883
bool IsSILFuncDecl = false);
883884

884-
/// \brief Parse any type, but diagnose all types except type-identifier or
885-
/// type-composition with non-type-identifier.
886-
///
887-
/// In some places the grammar allows only type-identifier, but when it is
888-
/// not ambiguous, we want to parse any type for recovery purposes.
889-
///
890-
/// \param MessageID a generic diagnostic for a syntax error in the type
891-
/// \param NonIdentifierTypeMessageID a diagnostic for a non-identifier type
892-
///
893-
/// \returns null, IdentTypeRepr, CompositionTypeRepr or ErrorTypeRepr.
894-
ParserResult<TypeRepr>
895-
parseTypeForInheritance(Diag<> MessageID,
896-
Diag<TypeLoc> NonIdentifierTypeMessageID);
897-
898885
ParserResult<TypeRepr> parseTypeSimpleOrComposition();
899886
ParserResult<TypeRepr>
900887
parseTypeSimpleOrComposition(Diag<> MessageID,

lib/AST/ConformanceLookupTable.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,13 @@ void ConformanceLookupTable::inheritConformances(ClassDecl *classDecl,
239239
superclassLoc = inherited.getSourceRange().Start;
240240
return superclassLoc;
241241
}
242+
if (inheritedType->isExistentialType()) {
243+
auto layout = inheritedType->getExistentialLayout();
244+
if (layout.superclass) {
245+
superclassLoc = inherited.getSourceRange().Start;
246+
return superclassLoc;
247+
}
248+
}
242249
}
243250
}
244251

lib/Parse/ParseDecl.cpp

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,7 +2651,8 @@ ParserResult<ImportDecl> Parser::parseDeclImport(ParseDeclOptions Flags,
26512651
/// type-identifier
26522652
/// \endverbatim
26532653
ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
2654-
bool allowClassRequirement) {
2654+
bool allowClassRequirement,
2655+
bool allowAnyObject) {
26552656
Scope S(this, ScopeKind::InheritanceClause);
26562657
consumeToken(tok::colon);
26572658

@@ -2665,9 +2666,16 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
26652666
// If we aren't allowed to have a class requirement here, complain.
26662667
auto classLoc = consumeToken();
26672668
if (!allowClassRequirement) {
2668-
SourceLoc endLoc = Tok.is(tok::comma) ? Tok.getLoc() : classLoc;
2669-
diagnose(classLoc, diag::invalid_class_requirement)
2670-
.fixItRemove(SourceRange(classLoc, endLoc));
2669+
diagnose(classLoc, diag::unexpected_class_constraint);
2670+
2671+
// Note that it makes no sense to suggest fixing
2672+
// 'struct S : class' to 'struct S : AnyObject' for
2673+
// example; in that case we just complain about
2674+
// 'class' being invalid here.
2675+
if (allowAnyObject) {
2676+
diagnose(classLoc, diag::suggest_anyobject)
2677+
.fixItReplace(classLoc, "AnyObject");
2678+
}
26712679
continue;
26722680
}
26732681

@@ -2697,44 +2705,9 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
26972705
continue;
26982706
}
26992707

2700-
bool usesDeprecatedCompositionSyntax =
2701-
Tok.is(tok::kw_protocol) && startsWithLess(peekToken());
2702-
bool isAny = Tok.is(tok::kw_Any); // We allow (redundant) inheritance from Any
2703-
2704-
auto ParsedTypeResult = parseTypeForInheritance(
2705-
diag::expected_identifier_for_type,
2706-
diag::expected_ident_type_in_inheritance);
2708+
auto ParsedTypeResult = parseType();
27072709
Status |= ParsedTypeResult;
27082710

2709-
// Recover and emit nice diagnostic for composition.
2710-
if (auto Composition = dyn_cast_or_null<CompositionTypeRepr>(
2711-
ParsedTypeResult.getPtrOrNull())) {
2712-
// Record the protocols inside the composition.
2713-
Inherited.append(Composition->getTypes().begin(),
2714-
Composition->getTypes().end());
2715-
// We can inherit from Any
2716-
if (!isAny) {
2717-
if (usesDeprecatedCompositionSyntax) {
2718-
// Provide fixits to remove the composition, leaving the types intact.
2719-
auto compositionRange = Composition->getCompositionRange();
2720-
auto token = Lexer::getTokenAtLocation(SourceMgr, compositionRange.End);
2721-
diagnose(Composition->getSourceLoc(),
2722-
diag::disallowed_protocol_composition)
2723-
.highlight({Composition->getStartLoc(), compositionRange.End})
2724-
.fixItRemove({Composition->getSourceLoc(), compositionRange.Start})
2725-
.fixItRemove(startsWithGreater(token)
2726-
? compositionRange.End
2727-
: SourceLoc());
2728-
} else {
2729-
diagnose(Composition->getStartLoc(),
2730-
diag::disallowed_protocol_composition)
2731-
.highlight(Composition->getSourceRange());
2732-
// TODO: Decompose 'A & B & C' list to 'A, B, C'
2733-
}
2734-
}
2735-
continue;
2736-
}
2737-
27382711
// Record the type if its a single type.
27392712
if (ParsedTypeResult.isNonNull())
27402713
Inherited.push_back(ParsedTypeResult.get());
@@ -2957,7 +2930,9 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
29572930
// Parse optional inheritance clause.
29582931
SmallVector<TypeLoc, 2> Inherited;
29592932
if (Tok.is(tok::colon))
2960-
status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);
2933+
status |= parseInheritance(Inherited,
2934+
/*allowClassRequirement=*/false,
2935+
/*allowAnyObject=*/false);
29612936

29622937
// Parse the optional where-clause.
29632938
TrailingWhereClause *trailingWhereClause = nullptr;
@@ -3296,7 +3271,9 @@ ParserResult<TypeDecl> Parser::parseDeclAssociatedType(Parser::ParseDeclOptions
32963271
// FIXME: Allow class requirements here.
32973272
SmallVector<TypeLoc, 2> Inherited;
32983273
if (Tok.is(tok::colon))
3299-
Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);
3274+
Status |= parseInheritance(Inherited,
3275+
/*allowClassRequirement=*/false,
3276+
/*allowAnyObject=*/true);
33003277

33013278
ParserResult<TypeRepr> UnderlyingTy;
33023279
if (Tok.is(tok::equal)) {
@@ -5036,7 +5013,9 @@ ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
50365013
// Parse optional inheritance clause within the context of the enum.
50375014
if (Tok.is(tok::colon)) {
50385015
SmallVector<TypeLoc, 2> Inherited;
5039-
Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);
5016+
Status |= parseInheritance(Inherited,
5017+
/*allowClassRequirement=*/false,
5018+
/*allowAnyObject=*/false);
50405019
ED->setInherited(Context.AllocateCopy(Inherited));
50415020
}
50425021

@@ -5296,7 +5275,9 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
52965275
// Parse optional inheritance clause within the context of the struct.
52975276
if (Tok.is(tok::colon)) {
52985277
SmallVector<TypeLoc, 2> Inherited;
5299-
Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);
5278+
Status |= parseInheritance(Inherited,
5279+
/*allowClassRequirement=*/false,
5280+
/*allowAnyObject=*/false);
53005281
SD->setInherited(Context.AllocateCopy(Inherited));
53015282
}
53025283

@@ -5381,7 +5362,9 @@ ParserResult<ClassDecl> Parser::parseDeclClass(SourceLoc ClassLoc,
53815362
// Parse optional inheritance clause within the context of the class.
53825363
if (Tok.is(tok::colon)) {
53835364
SmallVector<TypeLoc, 2> Inherited;
5384-
Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false);
5365+
Status |= parseInheritance(Inherited,
5366+
/*allowClassRequirement=*/false,
5367+
/*allowAnyObject=*/false);
53855368
CD->setInherited(Context.AllocateCopy(Inherited));
53865369
}
53875370

@@ -5469,7 +5452,8 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
54695452
if (Tok.is(tok::colon)) {
54705453
colonLoc = Tok.getLoc();
54715454
Status |= parseInheritance(InheritedProtocols,
5472-
/*allowClassRequirement=*/true);
5455+
/*allowClassRequirement=*/true,
5456+
/*allowAnyObject=*/true);
54735457
}
54745458

54755459
TrailingWhereClause *TrailingWhere = nullptr;

lib/Parse/ParseGeneric.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,10 @@ Parser::parseGenericParameters(SourceLoc LAngleLoc) {
7272
ParserResult<TypeRepr> Ty;
7373

7474
if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) {
75-
Ty = parseTypeForInheritance(diag::expected_identifier_for_type,
76-
diag::expected_ident_type_in_inheritance);
75+
Ty = parseType();
7776
} else if (Tok.is(tok::kw_class)) {
7877
diagnose(Tok, diag::unexpected_class_constraint);
79-
diagnose(Tok, diag::suggest_anyobject, Name)
78+
diagnose(Tok, diag::suggest_anyobject)
8079
.fixItReplace(Tok.getLoc(), "AnyObject");
8180
consumeToken();
8281
Invalid = true;
@@ -92,7 +91,7 @@ Parser::parseGenericParameters(SourceLoc LAngleLoc) {
9291
Inherited.push_back(Ty.get());
9392
}
9493

95-
// We always create generic type parameters with a depth of zero.
94+
// We always create generic type parameters with an invalid depth.
9695
// Semantic analysis fills in the depth when it processes the generic
9796
// parameter list.
9897
auto Param = new (Context) GenericTypeParamDecl(
@@ -289,9 +288,7 @@ ParserStatus Parser::parseGenericWhereClause(
289288
}
290289
} else {
291290
// Parse the protocol or composition.
292-
ParserResult<TypeRepr> Protocol =
293-
parseTypeForInheritance(diag::expected_identifier_for_type,
294-
diag::expected_ident_type_in_inheritance);
291+
ParserResult<TypeRepr> Protocol = parseType();
295292

296293
if (Protocol.isNull()) {
297294
Status.setIsParseError();

lib/Parse/ParseType.cpp

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -470,42 +470,6 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
470470
specifierLoc));
471471
}
472472

473-
ParserResult<TypeRepr> Parser::parseTypeForInheritance(
474-
Diag<> MessageID, Diag<TypeLoc> NonIdentifierTypeMessageID) {
475-
ParserResult<TypeRepr> Ty = parseTypeSimpleOrComposition(MessageID);
476-
477-
if (Ty.hasCodeCompletion())
478-
return makeParserCodeCompletionResult<TypeRepr>();
479-
480-
if (Ty.isParseError() || isa<ErrorTypeRepr>(Ty.get()))
481-
return Ty;
482-
483-
if (isa<IdentTypeRepr>(Ty.get()))
484-
return Ty;
485-
486-
if (auto Comp = dyn_cast<CompositionTypeRepr>(Ty.get())) {
487-
bool hasNonIdent = false;
488-
for (auto T : Comp->getTypes()) {
489-
if (isa<IdentTypeRepr>(T))
490-
continue;
491-
hasNonIdent = true;
492-
diagnose(T->getLoc(), NonIdentifierTypeMessageID, T)
493-
.highlight(T->getSourceRange());
494-
}
495-
// IdentType only composition are allowed.
496-
if (!hasNonIdent)
497-
return Ty;
498-
} else {
499-
diagnose(Ty.get()->getLoc(), NonIdentifierTypeMessageID, Ty.get())
500-
.highlight(Ty.get()->getSourceRange());
501-
}
502-
503-
return makeParserErrorResult(
504-
new (Context) ErrorTypeRepr(Ty.get()->getSourceRange()));
505-
506-
return Ty;
507-
}
508-
509473
bool Parser::parseGenericArguments(SmallVectorImpl<TypeRepr*> &Args,
510474
SourceLoc &LAngleLoc,
511475
SourceLoc &RAngleLoc) {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -490,8 +490,9 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
490490
if (inheritedTy->isExistentialType()) {
491491
auto layout = inheritedTy->getExistentialLayout();
492492

493-
// Classes and extensions cannot inherit from subclass
494-
// existentials or AnyObject.
493+
// Protocols, generic parameters and associated types can inherit
494+
// from subclass existentials, which are "exploded" into their
495+
// corresponding requirements.
495496
if (isa<ProtocolDecl>(decl) ||
496497
isa<AbstractTypeParamDecl>(decl) ||
497498
(!layout.hasExplicitAnyObject &&
@@ -503,7 +504,22 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
503504
continue;
504505
}
505506

506-
// Swift 3 compatibility:
507+
// Classes can inherit from subclass existentials as long as they
508+
// do not contain an explicit AnyObject member.
509+
if (isa<ClassDecl>(decl) &&
510+
!layout.hasExplicitAnyObject) {
511+
for (auto proto : layout.getProtocols()) {
512+
auto *protoDecl = proto->getDecl();
513+
allProtocols.insert(protoDecl);
514+
}
515+
516+
// Superclass inheritance is handled below.
517+
inheritedTy = layout.superclass;
518+
if (!inheritedTy)
519+
continue;
520+
}
521+
522+
// Swift 3 compatibility -- a class inheriting from AnyObject is a no-op.
507523
if (Context.LangOpts.isSwiftVersion3() && isa<ClassDecl>(decl) &&
508524
inheritedTy->isAnyObject()) {
509525
auto classDecl = cast<ClassDecl>(decl);

test/Parse/invalid.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ prefix operator %
135135
prefix func %<T>(x: T) -> T { return x } // No error expected - the < is considered an identifier but is peeled off by the parser.
136136

137137
struct Weak<T: class> { // expected-error {{'class' constraint can only appear on protocol declarations}}
138-
// expected-note@-1 {{did you mean to constrain 'T' with the 'AnyObject' protocol?}} {{16-21=AnyObject}}
138+
// expected-note@-1 {{did you mean to write an 'AnyObject' constraint?}} {{16-21=AnyObject}}
139139
weak let value: T // expected-error {{'weak' must be a mutable variable, because it may change at runtime}} expected-error {{'weak' variable should have optional type 'T?'}} expected-error {{'weak' may not be applied to non-class-bound 'T'; consider adding a protocol conformance that has a class bound}}
140140
}
141141

test/attr/attr_specialize.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public func funcWithTwoGenericParameters<X, Y>(x: X, y: Y) {
145145
@_specialize(kind: partial, exported: true, where X == Int, Y == Int)
146146
@_specialize(kind: partial, kind: partial, where X == Int, Y == Int) // expected-error{{parameter 'kind' was already defined in '_specialize' attribute}}
147147

148-
@_specialize(where X == Int, Y == Int, exported: true, kind: partial) // expected-error{{use of undeclared type 'exported'}} expected-error{{use of undeclared type 'kind'}} expected-error{{use of undeclared type 'partial'}} expected-error{{expected identifier for type name}}
148+
@_specialize(where X == Int, Y == Int, exported: true, kind: partial) // expected-error{{use of undeclared type 'exported'}} expected-error{{use of undeclared type 'kind'}} expected-error{{use of undeclared type 'partial'}} expected-error{{expected type}}
149149
public func anotherFuncWithTwoGenericParameters<X: P, Y>(x: X, y: Y) {
150150
}
151151

test/decl/class/classes.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,23 @@ class HDerived : H {
8585
override func f(_ x: Int) { }
8686
override class func f(_ x: Int) { }
8787
}
88+
89+
// Subclass existentials in inheritance clause
90+
protocol P {}
91+
protocol Q {}
92+
protocol R {}
93+
class Base : Q & R {}
94+
95+
class Derived : P & Base {}
96+
97+
func f(_: P) {}
98+
func g(_: Base) {}
99+
func h(_: Q) {}
100+
func i(_: R) {}
101+
102+
func testSubclassExistentialsInInheritanceClause() {
103+
f(Derived())
104+
g(Derived())
105+
h(Derived())
106+
i(Derived())
107+
}

0 commit comments

Comments
 (0)