Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4886,6 +4886,50 @@ bool Parser::isStartOfSwiftDecl(bool allowPoundIfAttributes) {
if (Tok.isContextualKeyword("macro") && Tok2.is(tok::identifier))
return true;

if (Tok.isContextualKeyword("package")) {
// If `case` is the next token after `return package` statement,
// E.g.
// switch package {
// case .x: return package
// case .y: return nil
// }
// currently it errors (this is also true for `open`).
//
// If a non-contextual keyword was used in the above example, this
// function hits the line from above:
// ```
// if (!Tok.isContextualDeclKeyword())
// return false;
// ```
// thus we return false here as well, i.e. treat it as a non-contextual
// keyword.
if (Tok2.getKind() == tok::kw_case)
return false;

// Handle 'package(set)' access modifier
auto DAK = DeclAttribute::getAttrKindFromString(Tok.getText());
if (DAK != DAK_Count && DeclAttribute::isDeclModifier(DAK)) {
BacktrackingScope backtrack(*this);
// First consume `package`
consumeToken();
// Eat paren after modifier name; e.g. `package(set)`, similar to
// `private(set)` described above in the `if (Tok.isKeyword())` block
if (consumeIf(tok::l_paren)) {
while (Tok.isNot(tok::r_brace, tok::eof, tok::pound_endif)) {
if (consumeIf(tok::r_paren))
break;
// If we found the start of a decl while trying to skip over the
// paren, then we have something incomplete like 'package('. Return
// true for better recovery.
if (isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false))
return true;
skipSingle();
}
}
return isStartOfSwiftDecl(/*allowPoundIfAttributes=*/false);
}
}

// If the next token is obviously not the start of a decl, bail early.
if (!isKeywordPossibleDeclStart(Context.LangOpts, Tok2))
return false;
Expand Down
66 changes: 66 additions & 0 deletions test/Sema/accessibility_package_contextual_keyword.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t

// RUN: %target-swift-frontend-typecheck -verify -disable-availability-checking %t/main.swift -package-name myPkg
// RUN: %target-swift-frontend-typecheck -verify -disable-availability-checking %t/A.swift -package-name myPkg
// RUN: %target-swift-frontend-typecheck -verify -disable-availability-checking %t/B.swift -package-name myPkg
// RUN: %target-swift-frontend-typecheck -verify -disable-availability-checking %t/D.swift -package-name myPkg
// RUN: not %target-swift-frontend-typecheck -verify -disable-availability-checking %t/C.swift -package-name myPkg 2>&1 | %FileCheck %s

//--- main.swift
package(set) public var a: String // should pass when `package` modifier is used at top level decls
public package(set) var b: String
package let c: Int
package var d: Int
package func f() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would calling a function named package still be accepted at the top level?

func package() {}
package()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes it works. I'll add them to the test

package func package() {}
package()

//--- A.swift
package class package { // package can be a type name
package init() {}
package var package: String? // package can be a var name
}

package class pkg {
package init() {}
package func package() {} // package can be a func name
package func package(arg: Int) {}
package func package(_ arg: Double) {}
}

public class MyClass {
var myVar1: package = package()
var myVar2: pkg = pkg()
func myFunc() {
_ = myVar1.package
myVar2.package()
myVar2.package(arg: 1)
myVar2.package(2.0)
}
}

//--- B.swift
public class Foo {
package(set) public var x: String?
public package(set) var y: Int?
}

//--- C.swift
public class Bar {
package package(set) package: String? // CHECK: warning: 'package(set)' modifier is redundant for a package var
package(set) package package: String? // CHECK: warning: 'package(set)' modifier is redundant for a package var
}

//--- D.swift
enum MyColor {
case red, green, blue
}
let packages: [MyColor] = [MyColor.red, MyColor.blue].compactMap { package in
switch package {
case .blue: return package // Should not error when `case` follows the `package` contextual keyword
case .red: return package
default: return nil
}
}

53 changes: 47 additions & 6 deletions test/attr/accessibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,10 @@ fileprivate(set)
public
var customSetter2 = 0

// FIXME: rdar://104931420 folowing should not error
// expected-error @+2{{cannot find 'package' in scope}}{{none}}
// expected-error @+1{{cannot find 'set' in scope; did you mean 'Set'?}}{{9-12=Set}}
package(set)
public
var customSetter3 = 0

// FIXME: rdar://104931420 folowing should not error
// expected-error @+1{{expected expression}}
public
package(set)
var customSetter4 = 0
Expand All @@ -66,6 +61,14 @@ public(set) // expected-error {{duplicate modifier}}
private // expected-error {{duplicate modifier}}
var customSetterDuplicateAttrsAllAround = 0

private(set) // expected-note {{modifier already specified here}}
package(set) // expected-error {{duplicate modifier}}
var customSetterDuplicateAttr2 = 0

package(set) // expected-note {{modifier already specified here}}
public(set) // expected-error {{duplicate modifier}}
public var customSetterDuplicateAttr3 = 0

private(get) // expected-error{{expected 'set' as subject of 'private' modifier}}
var invalidSubject = 0

Expand All @@ -75,6 +78,13 @@ var invalidSubject2 = 0
private(a bunch of random tokens) // expected-error{{expected 'set' as subject of 'private' modifier}} expected-error{{expected declaration}}
var invalidSubject3 = 0


package(get) // expected-error{{expected 'set' as subject of 'package' modifier}}
var invalidSubject4 = 0

package(42) // expected-error{{expected 'set' as subject of 'package' modifier}}
var invalidSubject5 = 0

private(set // expected-error{{expected ')' in 'private' modifier}}
var unterminatedSubject = 0

Expand Down Expand Up @@ -132,7 +142,9 @@ private protocol TestProtocol {
public(set) func publicSetFunc() {} // expected-error {{'public' modifier cannot be applied to this declaration}} {{1-13=}}

public(set) var defaultVis = 0 // expected-error {{internal variable cannot have a public setter}}

package(set) var defaultVisPkg = 0 // expected-error {{internal variable cannot have a package setter}}
package(set) package var defaultVisPkgPkg = 0 // expected-warning {{'package(set)' modifier is redundant for a package var}}
package(set) public var defaultVisPkgOK = 0 // OK
internal(set) private var privateVis = 0 // expected-error {{private variable cannot have an internal setter}}
private(set) var defaultVisOK = 0
private(set) public var publicVis = 0
Expand All @@ -144,8 +156,15 @@ private(set) var computedRW: Int {
get { return 42 }
set { }
}

package(set) public var computedPkg: Int { // expected-error {{'package(set)' modifier cannot be applied to read-only variables}} {{1-14=}}
return 42
}

private(set) let constant = 42 // expected-error {{'private(set)' modifier cannot be applied to constants}} {{1-14=}}

package(set) public let constantPkg = 42 // expected-error {{'package(set)' modifier cannot be applied to constants}} {{1-14=}}

public struct Properties {
private(set) var stored = 42
private(set) var computed: Int { // expected-error {{'private(set)' modifier cannot be applied to read-only properties}} {{3-16=}}
Expand All @@ -155,14 +174,30 @@ public struct Properties {
get { return 42 }
set { }
}

package(set) public var computedRWPkg: Int {
get { return 42 }
set { }
}

public package(set) var computedR: Int { // expected-error {{'package(set)' modifier cannot be applied to read-only properties}} {{10-23=}}
return 42
}

private(set) let constant = 42 // expected-error {{'private(set)' modifier cannot be applied to read-only properties}} {{3-16=}}
package(set) public let constantPkg = 42 // expected-error {{'package(set)' modifier cannot be applied to read-only properties}} {{3-16=}}
package(set) var defaultVisPkg = 42 // expected-error {{internal property cannot have a package setter}}
public(set) var defaultVis = 0 // expected-error {{internal property cannot have a public setter}}
open(set) var defaultVis2 = 0 // expected-error {{internal property cannot have an open setter}}

public(set) subscript(a a: Int) -> Int { // expected-error {{internal subscript cannot have a public setter}}
get { return 0 }
set {}
}
package(set) subscript(p p: Int) -> Int { // expected-error {{internal subscript cannot have a package setter}}
get { return 0 }
set {}
}
internal(set) private subscript(b b: Int) -> Int { // expected-error {{private subscript cannot have an internal setter}}
get { return 0 }
set {}
Expand All @@ -180,6 +215,10 @@ public struct Properties {
}

private extension Properties {
package(set) var extPropPkg: Int { // expected-error {{private property cannot have a package setter}}
get { return 42 }
set { }
}
public(set) var extProp: Int { // expected-error {{private property cannot have a public setter}}
get { return 42 }
set { }
Expand All @@ -198,11 +237,13 @@ private(set) extension Properties : EmptyProto2 {} // expected-error {{'private'
package protocol EmptyProto3 {}
package protocol EmptyProto4 {}
public protocol EmptyProto5 {}
public protocol EmptyProto6 {}

private extension Properties : EmptyProto3 {} // expected-error {{'private' modifier cannot be used with extensions that declare protocol conformances}} {{1-9=}}
private(set) extension Properties : EmptyProto4 {} // expected-error {{'private' modifier cannot be applied to this declaration}} {{1-14=}}

package extension Properties : EmptyProto5 {} // expected-error {{'package' modifier cannot be used with extensions that declare protocol conformances}} {{1-9=}}
package(set) extension Properties : EmptyProto6 {} // expected-error {{'package' modifier cannot be applied to this declaration}} {{1-14=}}

public struct PublicStruct {}
package struct PackageStruct {} // expected-note * {{declared here}}
Expand Down