Skip to content

Commit 3302b27

Browse files
Merge pull request #62775 from AnthonyLatsis/sugar-type-members-2
Parser: Support member types with non-identifier qualifiers
2 parents e6e7bd0 + 56a1809 commit 3302b27

19 files changed

+809
-288
lines changed

include/swift/AST/CASTBridging.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ void *ProtocolTypeRepr_create(void *ctx, void *baseType, void *protoLoc);
242242
void *PackExpansionTypeRepr_create(void *ctx, void *base, void *repeatLoc);
243243
void *TupleTypeRepr_create(void *ctx, BridgedArrayRef elements, void *lParenLoc,
244244
void *rParenLoc);
245-
void *DeclRefTypeRepr_create(void *ctx, BridgedArrayRef bridgedComponents);
245+
void *MemberTypeRepr_create(void *ctx, void *baseComponent,
246+
BridgedArrayRef bridgedMemberComponents);
246247
void *GenericIdentTypeRepr_create(void *ctx, BridgedIdentifier name,
247248
void *nameLoc, BridgedArrayRef genericArgs,
248249
void *lAngle, void *rAngle);

include/swift/AST/TypeRepr.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,11 @@ class MemberTypeRepr final : public DeclRefTypeRepr,
442442
}
443443

444444
public:
445-
static MemberTypeRepr *create(const ASTContext &Ctx, TypeRepr *Base,
446-
ArrayRef<IdentTypeRepr *> MemberComponents);
445+
static TypeRepr *create(const ASTContext &Ctx, TypeRepr *Base,
446+
ArrayRef<IdentTypeRepr *> MemberComponents);
447447

448-
static MemberTypeRepr *create(const ASTContext &Ctx,
449-
ArrayRef<IdentTypeRepr *> Components);
448+
static DeclRefTypeRepr *create(const ASTContext &Ctx,
449+
ArrayRef<IdentTypeRepr *> Components);
450450

451451
TypeRepr *getBaseComponent() const { return Base; }
452452

include/swift/IDE/CodeCompletionResult.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ enum class CompletionKind : uint8_t {
200200
KeyPathExprSwift,
201201
TypeDeclResultBeginning,
202202
TypeSimpleBeginning,
203-
TypeIdentifierWithDot,
204-
TypeIdentifierWithoutDot,
203+
TypeSimpleWithDot,
204+
TypeSimpleWithoutDot,
205205
CaseStmtKeyword,
206206
CaseStmtBeginning,
207207
NominalMemberBeginning,

include/swift/Parse/IDEInspectionCallbacks.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ class IDEInspectionCallbacks {
162162
/// by user.
163163
virtual void completeTypeSimpleBeginning() {};
164164

165-
/// Complete a given type identifier after we have consumed the dot.
166-
virtual void completeTypeIdentifierWithDot(DeclRefTypeRepr *TR){};
165+
/// Complete a given \c type-simple after we have consumed the dot.
166+
virtual void completeTypeSimpleWithDot(TypeRepr *TR){};
167167

168-
/// Complete a given type identifier when there is no trailing dot.
169-
virtual void completeTypeIdentifierWithoutDot(DeclRefTypeRepr *TR){};
168+
/// Complete a given \c type-simple when there is no trailing dot.
169+
virtual void completeTypeSimpleWithoutDot(TypeRepr *TR){};
170170

171171
/// Complete the beginning of a case statement at the top of switch stmt.
172172
virtual void completeCaseStmtKeyword() {};

include/swift/Parse/Parser.h

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ namespace llvm {
3939
}
4040

4141
namespace swift {
42+
class IdentTypeRepr;
4243
class IDEInspectionCallbacks;
4344
class IDEInspectionCallbacksFactory;
4445
class DefaultArgumentInitializer;
@@ -1327,19 +1328,29 @@ class Parser {
13271328
SourceLoc &LAngleLoc,
13281329
SourceLoc &RAngleLoc);
13291330

1330-
/// Parses a type identifier (e.g. 'Foo' or 'Foo.Bar.Baz').
1331+
/// Parses and returns the base type for a qualified declaration name,
1332+
/// positioning the parser at the '.' before the final declaration name. This
1333+
/// position is important for parsing final declaration names like '.init' via
1334+
/// `parseUnqualifiedDeclName`. For example, 'Foo.Bar.f' parses as 'Foo.Bar'
1335+
/// and the parser is positioned at '.f'. If there is no base type qualifier
1336+
/// (e.g. when parsing just 'f'), returns an empty parser error.
13311337
///
1332-
/// When `isParsingQualifiedDeclBaseType` is true:
1333-
/// - Parses and returns the base type for a qualified declaration name,
1334-
/// positioning the parser at the '.' before the final declaration name.
1335-
// This position is important for parsing final declaration names like
1336-
// '.init' via `parseUnqualifiedDeclName`.
1337-
/// - For example, 'Foo.Bar.f' parses as 'Foo.Bar' and the parser is
1338-
/// positioned at '.f'.
1339-
/// - If there is no base type qualifier (e.g. when parsing just 'f'), returns
1340-
/// an empty parser error.
1341-
ParserResult<TypeRepr> parseTypeIdentifier(
1342-
bool isParsingQualifiedDeclBaseType = false);
1338+
/// \verbatim
1339+
/// qualified-decl-name-base-type:
1340+
/// identifier generic-args? ('.' identifier generic-args?)*
1341+
/// \endverbatim
1342+
ParserResult<TypeRepr> parseQualifiedDeclNameBaseType();
1343+
1344+
/// Parse an identifier type, e.g 'Foo' or 'Bar<Int>'.
1345+
///
1346+
/// \verbatim
1347+
/// type-identifier: identifier generic-args?
1348+
/// \endverbatim
1349+
ParserResult<IdentTypeRepr> parseTypeIdentifier();
1350+
1351+
/// Parse a dotted type, e.g. 'Foo<X>.Y.Z', 'P.Type', '[X].Y'.
1352+
ParserResult<TypeRepr> parseTypeDotted(ParserResult<TypeRepr> Base);
1353+
13431354
ParserResult<TypeRepr> parseOldStyleProtocolComposition();
13441355
ParserResult<TypeRepr> parseAnyType();
13451356
ParserResult<TypeRepr> parseSILBoxType(GenericParamList *generics,
@@ -1587,10 +1598,7 @@ class Parser {
15871598
/// \verbatim
15881599
/// simple-type-identifier: identifier generic-argument-list?
15891600
/// \endverbatim
1590-
bool canParseSimpleTypeIdentifier();
1591-
15921601
bool canParseTypeIdentifier();
1593-
bool canParseTypeIdentifierOrTypeComposition();
15941602
bool canParseOldStyleProtocolComposition();
15951603
bool canParseTypeTupleBody();
15961604
bool canParseTypeAttribute();
@@ -1599,10 +1607,6 @@ class Parser {
15991607
bool canParseTypedPattern();
16001608

16011609
/// Returns true if a qualified declaration name base type can be parsed.
1602-
///
1603-
/// \verbatim
1604-
/// qualified-decl-name-base-type: simple-type-identifier '.'
1605-
/// \endverbatim
16061610
bool canParseBaseTypeForQualifiedDeclName();
16071611

16081612
/// Returns true if the current token is '->' or effects specifiers followed

lib/AST/CASTBridging.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -497,14 +497,13 @@ void *TupleTypeRepr_create(void *ctx, BridgedArrayRef elements, void *lParenLoc,
497497
SourceRange{lParen, rParen});
498498
}
499499

500-
void *DeclRefTypeRepr_create(void *ctx, BridgedArrayRef bridgedComponents) {
500+
void *MemberTypeRepr_create(void *ctx, void *baseComponent,
501+
BridgedArrayRef bridgedMemberComponents) {
501502
ASTContext &Context = *static_cast<ASTContext *>(ctx);
502-
auto components = getArrayRef<IdentTypeRepr *>(bridgedComponents);
503-
if (components.size() == 1) {
504-
return components.front();
505-
}
503+
auto memberComponents = getArrayRef<IdentTypeRepr *>(bridgedMemberComponents);
506504

507-
return MemberTypeRepr::create(Context, components);
505+
return MemberTypeRepr::create(Context, (TypeRepr *)baseComponent,
506+
memberComponents);
508507
}
509508

510509
void *CompositionTypeRepr_create(void *ctx, BridgedArrayRef types,

lib/AST/TypeRepr.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,17 +384,20 @@ GenericIdentTypeRepr *GenericIdentTypeRepr::create(const ASTContext &C,
384384
return new (mem) GenericIdentTypeRepr(Loc, Id, GenericArgs, AngleBrackets);
385385
}
386386

387-
MemberTypeRepr *
388-
MemberTypeRepr::create(const ASTContext &C, TypeRepr *Base,
389-
ArrayRef<IdentTypeRepr *> MemberComponents) {
387+
TypeRepr *MemberTypeRepr::create(const ASTContext &C, TypeRepr *Base,
388+
ArrayRef<IdentTypeRepr *> MemberComponents) {
389+
if (MemberComponents.empty())
390+
return Base;
391+
390392
auto size = totalSizeToAlloc<IdentTypeRepr *>(MemberComponents.size());
391393
auto mem = C.Allocate(size, alignof(MemberTypeRepr));
392394
return new (mem) MemberTypeRepr(Base, MemberComponents);
393395
}
394396

395-
MemberTypeRepr *MemberTypeRepr::create(const ASTContext &Ctx,
396-
ArrayRef<IdentTypeRepr *> Components) {
397-
return create(Ctx, Components.front(), Components.drop_front());
397+
DeclRefTypeRepr *MemberTypeRepr::create(const ASTContext &Ctx,
398+
ArrayRef<IdentTypeRepr *> Components) {
399+
return cast<DeclRefTypeRepr>(
400+
create(Ctx, Components.front(), Components.drop_front()));
398401
}
399402

400403
PackTypeRepr::PackTypeRepr(SourceLoc keywordLoc, SourceRange braceLocs,

lib/ASTGen/Sources/ASTGen/Types.swift

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,41 +28,40 @@ extension ASTGenVisitor {
2828
}
2929

3030
public func visit(_ node: MemberTypeIdentifierSyntax) -> ASTNode {
31-
var path = [(TokenSyntax, GenericArgumentClauseSyntax?)]()
32-
var memberRef: Syntax? = Syntax(node)
33-
while let nestedMember = memberRef?.as(MemberTypeIdentifierSyntax.self) {
34-
path.append((nestedMember.name, nestedMember.genericArgumentClause))
35-
memberRef = Syntax(nestedMember.baseType)
36-
}
31+
// Gather the member components, in decreasing depth order.
32+
var reverseMemberComponents = [UnsafeMutableRawPointer]()
3733

38-
if let base = memberRef?.as(SimpleTypeIdentifierSyntax.self) {
39-
path.append((base.name, base.genericArgumentClause))
40-
}
34+
var baseType = Syntax(node)
35+
while let memberType = baseType.as(MemberTypeIdentifierSyntax.self) {
36+
let nameToken = memberType.name
37+
let generics = memberType.genericArgumentClause
4138

42-
var elements = [UnsafeMutableRawPointer]()
43-
for (pathElement, generics) in path.reversed() {
44-
var nameText = pathElement.text
39+
var nameText = nameToken.text
4540
let name = nameText.withUTF8 { buf in
4641
return SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count)
4742
}
48-
let nameLoc = self.base.advanced(by: pathElement.position.utf8Offset).raw
43+
let nameLoc = self.base.advanced(by: nameToken.position.utf8Offset).raw
4944

5045
if let generics = generics {
5146
let lAngle = self.base.advanced(by: generics.leftAngleBracket.position.utf8Offset).raw
5247
let rAngle = self.base.advanced(by: generics.rightAngleBracket.position.utf8Offset).raw
53-
elements.append(
48+
reverseMemberComponents.append(
5449
generics.arguments.map({ self.visit($0.argumentType) }).withBridgedArrayRef {
5550
genericArgs in
5651
GenericIdentTypeRepr_create(self.ctx, name, nameLoc, genericArgs, lAngle, rAngle)
5752
})
5853
} else {
59-
elements.append(SimpleIdentTypeRepr_create(self.ctx, nameLoc, name))
54+
reverseMemberComponents.append(SimpleIdentTypeRepr_create(self.ctx, nameLoc, name))
6055
}
56+
57+
baseType = Syntax(memberType.baseType)
6158
}
6259

60+
let baseComponent = visit(baseType).rawValue
61+
6362
return .type(
64-
elements.withBridgedArrayRef { elements in
65-
return DeclRefTypeRepr_create(self.ctx, elements)
63+
reverseMemberComponents.reversed().withBridgedArrayRef { memberComponents in
64+
return MemberTypeRepr_create(self.ctx, baseComponent, memberComponents)
6665
})
6766
}
6867

lib/IDE/CodeCompletion.cpp

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,8 @@ class CodeCompletionCallbacksImpl : public IDEInspectionCallbacks {
266266

267267
void completeTypeDeclResultBeginning() override;
268268
void completeTypeSimpleBeginning() override;
269-
void completeTypeIdentifierWithDot(DeclRefTypeRepr *TR) override;
270-
void completeTypeIdentifierWithoutDot(DeclRefTypeRepr *TR) override;
269+
void completeTypeSimpleWithDot(TypeRepr *TR) override;
270+
void completeTypeSimpleWithoutDot(TypeRepr *TR) override;
271271

272272
void completeCaseStmtKeyword() override;
273273
void completeCaseStmtBeginning(CodeCompletionExpr *E) override;
@@ -494,21 +494,16 @@ void CodeCompletionCallbacksImpl::completeInPrecedenceGroup(
494494
CurDeclContext = P.CurDeclContext;
495495
}
496496

497-
void CodeCompletionCallbacksImpl::completeTypeIdentifierWithDot(
498-
DeclRefTypeRepr *TR) {
499-
if (!TR) {
500-
completeTypeSimpleBeginning();
501-
return;
502-
}
503-
Kind = CompletionKind::TypeIdentifierWithDot;
497+
void CodeCompletionCallbacksImpl::completeTypeSimpleWithDot(TypeRepr *TR) {
498+
assert(TR);
499+
Kind = CompletionKind::TypeSimpleWithDot;
504500
ParsedTypeLoc = TypeLoc(TR);
505501
CurDeclContext = P.CurDeclContext;
506502
}
507503

508-
void CodeCompletionCallbacksImpl::completeTypeIdentifierWithoutDot(
509-
DeclRefTypeRepr *TR) {
504+
void CodeCompletionCallbacksImpl::completeTypeSimpleWithoutDot(TypeRepr *TR) {
510505
assert(TR);
511-
Kind = CompletionKind::TypeIdentifierWithoutDot;
506+
Kind = CompletionKind::TypeSimpleWithoutDot;
512507
ParsedTypeLoc = TypeLoc(TR);
513508
CurDeclContext = P.CurDeclContext;
514509
}
@@ -953,6 +948,13 @@ addClosureSignatureKeywordsIfApplicable(CodeCompletionResultSink &Sink,
953948

954949
void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
955950
bool MaybeFuncBody) {
951+
auto addEffectsSpecifierKeywords = [&] {
952+
if (!llvm::is_contained(ParsedKeywords, "async"))
953+
addKeyword(Sink, "async", CodeCompletionKeywordKind::None);
954+
if (!llvm::is_contained(ParsedKeywords, "throws"))
955+
addKeyword(Sink, "throws", CodeCompletionKeywordKind::kw_throws);
956+
};
957+
956958
switch (Kind) {
957959
case CompletionKind::None:
958960
case CompletionKind::DotExpr:
@@ -974,13 +976,9 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
974976
case CompletionKind::OptionalBinding:
975977
break;
976978

977-
case CompletionKind::EffectsSpecifier: {
978-
if (!llvm::is_contained(ParsedKeywords, "async"))
979-
addKeyword(Sink, "async", CodeCompletionKeywordKind::None);
980-
if (!llvm::is_contained(ParsedKeywords, "throws"))
981-
addKeyword(Sink, "throws", CodeCompletionKeywordKind::kw_throws);
979+
case CompletionKind::EffectsSpecifier:
980+
addEffectsSpecifierKeywords();
982981
break;
983-
}
984982

985983
case CompletionKind::AccessorBeginning: {
986984
// TODO: Omit already declared or mutally exclusive accessors.
@@ -1037,8 +1035,15 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
10371035

10381036
break;
10391037
case CompletionKind::CaseStmtBeginning:
1040-
case CompletionKind::TypeIdentifierWithDot:
1041-
case CompletionKind::TypeIdentifierWithoutDot:
1038+
case CompletionKind::TypeSimpleWithDot:
1039+
break;
1040+
1041+
case CompletionKind::TypeSimpleWithoutDot:
1042+
// Suggest effects specifiers after a tuple type because it may be
1043+
// intended as a parameter list.
1044+
if (isa_and_nonnull<TupleTypeRepr>(ParsedTypeLoc.getTypeRepr())) {
1045+
addEffectsSpecifierKeywords();
1046+
}
10421047
break;
10431048

10441049
case CompletionKind::TypeDeclResultBeginning: {
@@ -1241,8 +1246,8 @@ void swift::ide::postProcessCompletionResults(
12411246
if (result->getKind() == CodeCompletionResultKind::Declaration &&
12421247
result->getAssociatedDeclKind() == CodeCompletionDeclKind::Protocol &&
12431248
Kind != CompletionKind::TypeSimpleBeginning &&
1244-
Kind != CompletionKind::TypeIdentifierWithoutDot &&
1245-
Kind != CompletionKind::TypeIdentifierWithDot &&
1249+
Kind != CompletionKind::TypeSimpleWithoutDot &&
1250+
Kind != CompletionKind::TypeSimpleWithDot &&
12461251
Kind != CompletionKind::TypeDeclResultBeginning &&
12471252
Kind != CompletionKind::GenericRequirement) {
12481253
flair |= CodeCompletionFlairBit::RareTypeAtCurrentPosition;
@@ -1597,7 +1602,7 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
15971602
return;
15981603

15991604
undoSingleExpressionReturn(CurDeclContext);
1600-
if (Kind != CompletionKind::TypeIdentifierWithDot) {
1605+
if (Kind != CompletionKind::TypeSimpleWithDot) {
16011606
// Type member completion does not need a type-checked AST.
16021607
typeCheckContextAt(
16031608
TypeCheckASTNodeAtLocContext::declContext(CurDeclContext),
@@ -1753,13 +1758,13 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17531758
break;
17541759
}
17551760

1756-
case CompletionKind::TypeIdentifierWithDot: {
1761+
case CompletionKind::TypeSimpleWithDot: {
17571762
Lookup.setHaveDot(SourceLoc());
17581763
Lookup.getTypeCompletions(ParsedTypeLoc.getType());
17591764
break;
17601765
}
17611766

1762-
case CompletionKind::TypeIdentifierWithoutDot: {
1767+
case CompletionKind::TypeSimpleWithoutDot: {
17631768
Lookup.getTypeCompletions(ParsedTypeLoc.getType());
17641769
break;
17651770
}

lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,7 +1434,7 @@ static Optional<AccessorKind> isAccessorLabel(const Token &token) {
14341434
return None;
14351435
}
14361436

1437-
/// Helper function that parses 'type-identifier' for `parseQualifiedDeclName`.
1437+
/// Helper function that parses a base type for `parseQualifiedDeclName`.
14381438
/// Returns true on error. Sets `baseType` to the parsed base type if present,
14391439
/// or to `nullptr` if not. A missing base type is not considered an error.
14401440
static bool parseBaseTypeForQualifiedDeclName(Parser &P, TypeRepr *&baseType) {
@@ -1445,15 +1445,15 @@ static bool parseBaseTypeForQualifiedDeclName(Parser &P, TypeRepr *&baseType) {
14451445
if (!P.canParseBaseTypeForQualifiedDeclName())
14461446
return false;
14471447

1448-
auto result = P.parseTypeIdentifier(/*isParsingQualifiedDeclName*/ true);
1448+
auto result = P.parseQualifiedDeclNameBaseType();
14491449
// If base type should be parseable but the actual base type result is null,
14501450
// return true (error).
14511451
if (result.isNull())
14521452
return true;
14531453

14541454
// Consume the leading period before the final declaration name component.
1455-
// `parseTypeIdentifier(/*isParsingQualifiedDeclName*/ true)` leaves the
1456-
// leading period unparsed to avoid syntax verification errors.
1455+
// `parseQualifiedDeclNameBaseType` leaves the leading period unparsed to
1456+
// avoid syntax verification errors.
14571457
assert(P.startsWithSymbol(P.Tok, '.') && "false");
14581458

14591459
// Check if this is a reference to a property or subscript accessor.
@@ -1489,9 +1489,7 @@ static bool parseBaseTypeForQualifiedDeclName(Parser &P, TypeRepr *&baseType) {
14891489
///
14901490
/// \verbatim
14911491
/// qualified-decl-name:
1492-
/// type-identifier? unqualified-decl-name
1493-
/// type-identifier:
1494-
/// identifier generic-args? ('.' identifier generic-args?)*
1492+
/// qualified-decl-name-base-type? unqualified-decl-name
14951493
/// \endverbatim
14961494
///
14971495
// TODO(TF-1066): Use module qualified name syntax/parsing instead of custom

0 commit comments

Comments
 (0)