Skip to content

Commit 7a1cf71

Browse files
committed
Parse module selectors in permitted locations
1 parent 36d3ef2 commit 7a1cf71

File tree

7 files changed

+239
-15
lines changed

7 files changed

+239
-15
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ ERROR(forbidden_interpolated_string,none,
9191
ERROR(forbidden_extended_escaping_string,none,
9292
"%0 cannot be an extended escaping string literal", (StringRef))
9393

94+
ERROR(expected_identifier_in_module_selector,none,
95+
"expected identifier in module selector", ())
96+
ERROR(module_selector_not_allowed_here,none,
97+
"name cannot be qualified with module selector here", ())
98+
9499
//------------------------------------------------------------------------------
95100
// MARK: Lexer diagnostics
96101
//------------------------------------------------------------------------------

include/swift/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,10 @@ class Parser {
16281628
/// not ordinary identifiers.
16291629
AllowKeywordsUsingSpecialNames = AllowKeywords | 1 << 2,
16301630

1631+
/// If passed, a module selector (ModuleName::) is permitted before the base
1632+
/// name.
1633+
AllowModuleSelector = 1 << 3,
1634+
16311635
/// If passed, compound names with argument lists are allowed, unless they
16321636
/// have empty argument lists.
16331637
AllowCompoundNames = 1 << 4,

lib/Parse/ParseDecl.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,7 +1189,8 @@ static bool parseQualifiedDeclName(Parser &P, Diag<> nameParseError,
11891189
original.Loc, nameParseError,
11901190
Parser::DeclNameFlag::AllowZeroArgCompoundNames |
11911191
Parser::DeclNameFlag::AllowKeywordsUsingSpecialNames |
1192-
Parser::DeclNameFlag::AllowOperators);
1192+
Parser::DeclNameFlag::AllowOperators |
1193+
Parser::DeclNameFlag::AllowModuleSelector);
11931194
// The base type is optional, but the final unqualified declaration name is
11941195
// not. If name could not be parsed, return true for error.
11951196
if (!original.Name)
@@ -2484,7 +2485,8 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
24842485
diag::attr_dynamic_replacement_expected_function,
24852486
DeclNameFlag::AllowZeroArgCompoundNames |
24862487
DeclNameFlag::AllowKeywordsUsingSpecialNames |
2487-
DeclNameFlag::AllowOperators);
2488+
DeclNameFlag::AllowOperators |
2489+
DeclNameFlag::AllowModuleSelector);
24882490
}
24892491

24902492
// Parse the matching ')'.
@@ -2830,11 +2832,15 @@ ParserStatus Parser::parseDeclAttribute(
28302832
DeclAttributes &Attributes, SourceLoc AtLoc,
28312833
PatternBindingInitializer *&initContext,
28322834
bool isFromClangAttribute) {
2835+
bool hasModuleSelector = Context.LangOpts.EnableExperimentalModuleSelector &&
2836+
peekToken().is(tok::colon_colon);
2837+
28332838
// If this not an identifier, the attribute is malformed.
28342839
if (Tok.isNot(tok::identifier) &&
28352840
Tok.isNot(tok::kw_in) &&
28362841
Tok.isNot(tok::kw_inout) &&
2837-
Tok.isNot(tok::kw_rethrows)) {
2842+
Tok.isNot(tok::kw_rethrows) &&
2843+
!hasModuleSelector) {
28382844

28392845
if (Tok.is(tok::code_complete)) {
28402846
if (CodeCompletion) {
@@ -2854,15 +2860,18 @@ ParserStatus Parser::parseDeclAttribute(
28542860

28552861
// If the attribute follows the new representation, switch
28562862
// over to the alternate parsing path.
2857-
DeclAttrKind DK = DeclAttribute::getAttrKindFromString(Tok.getText());
2863+
// All module-selected names are custom attributes, so we always use DAK_Count
2864+
// if a module selector is present.
2865+
DeclAttrKind DK = hasModuleSelector ? DAK_Count :
2866+
DeclAttribute::getAttrKindFromString(Tok.getText());
28582867
if (DK == DAK_Rethrows) { DK = DAK_AtRethrows; }
28592868
if (DK == DAK_Reasync) { DK = DAK_AtReasync; }
28602869

28612870
auto checkInvalidAttrName = [&](StringRef invalidName,
28622871
StringRef correctName,
28632872
DeclAttrKind kind,
28642873
Optional<Diag<StringRef, StringRef>> diag = None) {
2865-
if (DK == DAK_Count && Tok.getText() == invalidName) {
2874+
if (DK == DAK_Count && !hasModuleSelector && Tok.getText() == invalidName) {
28662875
DK = kind;
28672876

28682877
if (diag) {
@@ -2916,7 +2925,8 @@ ParserStatus Parser::parseDeclAttribute(
29162925
AtLoc = SourceLoc();
29172926
}
29182927

2919-
if (DK == DAK_Count && Tok.getText() == "warn_unused_result") {
2928+
if (DK == DAK_Count && !hasModuleSelector
2929+
&& Tok.getText() == "warn_unused_result") {
29202930
// The behavior created by @warn_unused_result is now the default. Emit a
29212931
// Fix-It to remove.
29222932
SourceLoc attrLoc = consumeToken();
@@ -2957,9 +2967,10 @@ ParserStatus Parser::parseDeclAttribute(
29572967
return makeParserSuccess();
29582968
}
29592969

2960-
if (TypeAttributes::getAttrKindFromString(Tok.getText()) != TAK_Count)
2970+
if (!hasModuleSelector &&
2971+
TypeAttributes::getAttrKindFromString(Tok.getText()) != TAK_Count)
29612972
diagnose(Tok, diag::type_attribute_applied_to_decl);
2962-
else if (Tok.isContextualKeyword("unknown")) {
2973+
else if (!hasModuleSelector && Tok.isContextualKeyword("unknown")) {
29632974
diagnose(Tok, diag::unknown_attribute, "unknown");
29642975
} else {
29652976
// Change the context to create a custom attribute syntax.
@@ -3118,7 +3129,8 @@ bool Parser::parseConventionAttributeInternal(
31183129

31193130
DeclNameLoc unusedLoc;
31203131
convention.WitnessMethodProtocol = parseDeclNameRef(unusedLoc,
3121-
diag::convention_attribute_witness_method_expected_protocol, {});
3132+
diag::convention_attribute_witness_method_expected_protocol,
3133+
DeclNameFlag::AllowModuleSelector);
31223134
}
31233135

31243136
// Parse the ')'. We can't use parseMatchingToken if we're in

lib/Parse/ParseExpr.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,7 +1198,8 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
11981198
? diag::expected_identifier_after_super_dot_expr
11991199
: diag::expected_member_name;
12001200
auto Name = parseDeclNameRef(NameLoc, D,
1201-
DeclNameFlag::AllowKeywords | DeclNameFlag::AllowCompoundNames);
1201+
DeclNameFlag::AllowKeywords | DeclNameFlag::AllowCompoundNames |
1202+
DeclNameFlag::AllowModuleSelector);
12021203
if (!Name) {
12031204
SourceRange ErrorRange = Result.get()->getSourceRange();
12041205
ErrorRange.widen(TokLoc);
@@ -1726,7 +1727,8 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
17261727
}
17271728

17281729
Name = parseDeclNameRef(NameLoc, diag::expected_identifier_after_dot_expr,
1729-
DeclNameFlag::AllowKeywords | DeclNameFlag::AllowCompoundNames);
1730+
DeclNameFlag::AllowKeywords | DeclNameFlag::AllowCompoundNames |
1731+
DeclNameFlag::AllowModuleSelector);
17301732
if (!Name)
17311733
return makeParserErrorResult(new (Context) ErrorExpr(DotLoc));
17321734
SyntaxContext->createNodeInPlace(SyntaxKind::MemberAccessExpr);
@@ -2270,6 +2272,34 @@ DeclNameRef Parser::parseDeclNameRef(DeclNameLoc &loc,
22702272
DeclNameOptions flags) {
22712273
SyntaxParsingContext declNameRefCtxt(SyntaxContext, SyntaxKind::DeclNameRef);
22722274

2275+
// Consume the module name, if present.
2276+
SourceLoc moduleSelectorLoc;
2277+
Identifier moduleSelector;
2278+
if (Context.LangOpts.EnableExperimentalModuleSelector &&
2279+
peekToken().is(tok::colon_colon)) {
2280+
// FIXME: libSyntax
2281+
2282+
if (Tok.is(tok::identifier)) { // FIXME: tok::dollarident?
2283+
moduleSelectorLoc = consumeIdentifier(moduleSelector,
2284+
/*diagnoseDollarPrefix=*/true);
2285+
}
2286+
else {
2287+
diagnose(Tok, diag::expected_identifier_in_module_selector);
2288+
moduleSelector = Identifier();
2289+
moduleSelectorLoc = consumeToken();
2290+
}
2291+
2292+
// Diagnose if we don't allow a module selector here.
2293+
if (!flags.contains(DeclNameFlag::AllowModuleSelector)) {
2294+
diagnose(Tok, diag::module_selector_not_allowed_here)
2295+
.fixItRemove({moduleSelectorLoc, Tok.getLoc()});
2296+
moduleSelector = Identifier();
2297+
moduleSelectorLoc = SourceLoc();
2298+
}
2299+
2300+
consumeToken(tok::colon_colon);
2301+
}
2302+
22732303
// Consume the base name.
22742304
DeclBaseName baseName;
22752305
SourceLoc baseNameLoc;
@@ -2342,7 +2372,8 @@ ParserResult<Expr> Parser::parseExprIdentifier() {
23422372
// Parse the unqualified-decl-name.
23432373
DeclNameLoc loc;
23442374
DeclNameRef name = parseDeclNameRef(loc, diag::expected_expr,
2345-
DeclNameFlag::AllowCompoundNames);
2375+
DeclNameFlag::AllowCompoundNames |
2376+
DeclNameFlag::AllowModuleSelector);
23462377

23472378
SmallVector<TypeRepr*, 8> args;
23482379
SourceLoc LAngleLoc, RAngleLoc;
@@ -3188,8 +3219,11 @@ ParserStatus Parser::parseExprList(tok leftTok, tok rightTok,
31883219
SyntaxParsingContext operatorContext(SyntaxContext,
31893220
SyntaxKind::IdentifierExpr);
31903221
DeclNameLoc Loc;
3222+
// FIXME: We would like to allow module selectors on binary operators, but
3223+
// the condition above won't let us reach this code.
31913224
auto OperName = parseDeclNameRef(Loc, diag::expected_operator_ref,
3192-
DeclNameFlag::AllowOperators);
3225+
DeclNameFlag::AllowOperators |
3226+
DeclNameFlag::AllowModuleSelector);
31933227
if (!OperName) {
31943228
return makeParserError();
31953229
}

lib/Parse/ParseType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,8 @@ Parser::parseTypeIdentifier(bool isParsingQualifiedDeclBaseType) {
700700
while (true) {
701701
DeclNameLoc Loc;
702702
DeclNameRef Name =
703-
parseDeclNameRef(Loc, diag::expected_identifier_in_dotted_type, {});
703+
parseDeclNameRef(Loc, diag::expected_identifier_in_dotted_type,
704+
DeclNameFlag::AllowModuleSelector);
704705
if (!Name)
705706
Status.setIsParseError();
706707

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-module-flags: -module-name ModuleSelectorTestingKit -swift-version 5
3+
4+
import Swift
5+
6+
// These types are identical; we just use them to test with different scope
7+
// selectors.
8+
9+
public struct A {
10+
public init(value: Swift.Int)
11+
public dynamic mutating func negate()
12+
public var magnitude: Swift.UInt
13+
}
14+
15+
public struct B {
16+
public init(value: Swift.Int)
17+
public dynamic mutating func negate()
18+
public var magnitude: Swift.UInt
19+
}
20+
21+
public struct C {
22+
public init(value: Int)
23+
public dynamic mutating func negate()
24+
public var magnitude: Swift.UInt
25+
}
26+
27+
public struct D {
28+
public init(value: Int)
29+
public dynamic mutating func negate()
30+
public var magnitude: Swift.UInt
31+
}
32+
33+
@propertyWrapper
34+
public struct available {
35+
public init() {}
36+
public var wrappedValue: Int { 0 }
37+
}
38+
39+
@_functionBuilder
40+
public struct MyBuilder {
41+
public static func buildBlock()
42+
}

test/NameLookup/module_selector.swift

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,127 @@
1-
// RUN: %target-typecheck-verify-swift -enable-experimental-module-selector %s
1+
// RUN: %target-typecheck-verify-swift -module-name main -I %S/Inputs -enable-experimental-module-selector
2+
3+
// Make sure the lack of the experimental flag disables the feature:
4+
// RUN: not %target-typecheck-verify-swift -module-name main -I %S/Inputs 2>/dev/null
5+
6+
import ModuleSelectorTestingKit
7+
8+
let magnitude: Never = fatalError()
9+
10+
// Test resolution of main:: using `B`
11+
12+
extension main::B: main::Equatable {
13+
@_implements(main::Equatable, main::==(_:_:)) // expected-error {{name cannot be qualified with module selector here}} {{33-39=}}
14+
public static func equals(_: main::B, _: main::B) -> main::Bool { main::fatalError() }
15+
16+
// FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and
17+
// @_derivative(of:)
18+
19+
@_dynamicReplacement(for: main::negate())
20+
mutating func myNegate() {
21+
let fn: (main::Int, main::Int) -> main::Int =
22+
// FIXME:
23+
(main::+) // expected-error {{cannot convert value of type '()' to specified type '(Int, Int) -> Int'}} expected-error {{expected expression}} expected-error {{expected expression after operator}}
24+
let magnitude: main::Int.main::Magnitude = main::magnitude // expected-EVENTUALLY-error {{a type mismatch with 'Never'}} FIXME: expected-error {{variable used within its own initial value}}
25+
if main::Bool.main::random() {
26+
main::negate() // expected-EVENTUALLY-error {{something about not finding 'negate' because we didn't look in self}}
27+
}
28+
else {
29+
self = main::B(value: .main::min)
30+
}
31+
32+
self.main::myNegate()
33+
}
34+
35+
// FIXME: Can we test @convention(witness_method:)?
36+
}
37+
38+
// Test resolution of ModuleSelectorTestingKit:: using `C`
39+
40+
extension ModuleSelectorTestingKit::C: ModuleSelectorTestingKit::Equatable {
41+
@_implements(ModuleSelectorTestingKit::Equatable, ModuleSelectorTestingKit::==(_:_:)) // expected-error {{name cannot be qualified with module selector here}} {{52-77=}}
42+
public static func equals(_: ModuleSelectorTestingKit::C, _: ModuleSelectorTestingKit::C) -> ModuleSelectorTestingKit::Bool { ModuleSelectorTestingKit::fatalError() }
43+
44+
// FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and
45+
// @_derivative(of:)
46+
47+
@_dynamicReplacement(for: ModuleSelectorTestingKit::negate())
48+
mutating func myNegate() {
49+
let fn: (ModuleSelectorTestingKit::Int, ModuleSelectorTestingKit::Int) -> ModuleSelectorTestingKit::Int =
50+
// FIXME:
51+
(ModuleSelectorTestingKit::+) // expected-error {{cannot convert value of type '()' to specified type '(Int, Int) -> Int'}} expected-error {{expected expression}} expected-error {{expected expression after operator}}
52+
let magnitude: ModuleSelectorTestingKit::Int.ModuleSelectorTestingKit::Magnitude = ModuleSelectorTestingKit::magnitude // expected-EVENTUALLY-error {{something about not finding 'magnitude' because we didn't look in self}} FIXME: expected-error {{variable used within its own initial value}}
53+
if ModuleSelectorTestingKit::Bool.ModuleSelectorTestingKit::random() {
54+
ModuleSelectorTestingKit::negate() // expected-EVENTUALLY-error {{something about not finding 'negate' because we didn't look in self}}
55+
}
56+
else {
57+
self = ModuleSelectorTestingKit::C(value: .ModuleSelectorTestingKit::min)
58+
}
59+
60+
self.ModuleSelectorTestingKit::myNegate() // expected-EVENTUALLY-error {{can't find 'myNegate' in ModuleSelectorTestingKit}}
61+
}
62+
63+
// FIXME: Can we test @convention(witness_method:)?
64+
}
65+
66+
// Test resolution of Swift:: using `D`
67+
// FIXME: Many more of these should fail once the feature is actually implemented.
68+
69+
extension Swift::D: Swift::Equatable {
70+
@_implements(Swift::Equatable, Swift::==(_:_:)) // expected-error {{name cannot be qualified with module selector here}} {{34-41=}}
71+
public static func equals(_: Swift::D, _: Swift::D) -> Swift::Bool { Swift::fatalError() }
72+
73+
// FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and
74+
// @_derivative(of:)
75+
76+
@_dynamicReplacement(for: Swift::negate())
77+
mutating func myNegate() {
78+
let fn: (Swift::Int, Swift::Int) -> Swift::Int =
79+
// FIXME:
80+
(Swift::+) // expected-error {{cannot convert value of type '()' to specified type '(Int, Int) -> Int'}} expected-error {{expected expression}} expected-error {{expected expression after operator}}
81+
let magnitude: Swift::Int.Swift::Magnitude = Swift::magnitude // expected-EVENTUALLY-error {{something about not finding 'magnitude' because we didn't look in self}} FIXME: expected-error {{variable used within its own initial value}}
82+
if Swift::Bool.Swift::random() {
83+
Swift::negate() // expected-EVENTUALLY-error {{something about not finding 'negate' because we didn't look in self}}
84+
}
85+
else {
86+
self = Swift::D(value: .ModuleSelectorTestingKit::min)
87+
}
88+
89+
self.Swift::myNegate() // expected-EVENTUALLY-error {{can't find 'myNegate' in Swift}}
90+
}
91+
92+
// FIXME: Can we test @convention(witness_method:)?
93+
}
94+
95+
struct AvailableUser {
96+
@available(macOS 10.15, *) var use1: String { "foo" }
97+
98+
@main::available() var use2
99+
@ModuleSelectorTestingKit::available() var use4
100+
@Swift::available() var use5 // expected-EVENTUALLY-error {{can't find because not in 'Swift'}}
101+
}
102+
103+
func builderUser2(@main::MyBuilder fn: () -> Void) {}
104+
func builderUser3(@ModuleSelectorTestingKit::MyBuilder fn: () -> Void) {}
105+
func builderUser4(@Swift::MyBuilder fn: () -> Void) {} // expected-EVENTUALLY-error {{can't find because not in 'Swift'}}
106+
107+
func whitespace() {
108+
Swift::print // expected-error{{expression resolves to an unused function}}
109+
110+
Swift :: print // expected-error{{expression resolves to an unused function}}
111+
112+
Swift::
113+
print // expected-error{{expression resolves to an unused function}}
114+
115+
Swift
116+
::print // expected-error{{expression resolves to an unused function}}
117+
118+
Swift ::
119+
print // expected-error{{expression resolves to an unused function}}
120+
121+
Swift
122+
:: print // expected-error{{expression resolves to an unused function}}
123+
124+
Swift
125+
::
126+
print // expected-error{{expression resolves to an unused function}}
127+
}

0 commit comments

Comments
 (0)