Skip to content

Commit 30a30e1

Browse files
committed
Pull SE-0081 into Swift 3.0 Preview 1 (#2850)
* Implement parser support for SE-0081 - Move 'where' clause to end of declaration This patch includes testsuite changes to show each of the decls supported. Next step is to migrate the stdlib + testsuite + corelibs: I'd would *greatly* appreciate help with this. After that is done, deprecation + migration of the old form can happen. * My recent patch "broke" these tests, but allowing the syntax in them to trigger existing generics bugs.
1 parent eedae5a commit 30a30e1

17 files changed

+159
-44
lines changed

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,32 @@ Note: This is in reverse chronological order, so newer entries are added to the
33
Swift 3.0
44
---------
55

6+
* [SE-0081](https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md)
7+
"Move 'where' clause to end of declaration" is implemented, allowing you to
8+
write 'where' clauses after the signature for a declaration, but before its
9+
body. For example, before:
10+
11+
```swift
12+
func anyCommonElements<T : SequenceType, U : SequenceType
13+
where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element>
14+
(lhs: T, _ rhs: U) -> Bool
15+
{
16+
...
17+
}
18+
```
19+
20+
after:
21+
22+
```swift
23+
func anyCommonElements<T : SequenceType, U : SequenceType>(lhs: T, _ rhs: U) -> Bool
24+
where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element>
25+
{
26+
...
27+
}
28+
```
29+
30+
The old form is still accepted for compatibility, but will eventually be rejected.
31+
632
* [SE-0071](https://github.com/apple/swift-evolution/blob/master/proposals/0071-member-keywords.md):
733
"Allow (most) keywords in member references" is implemented. This allows the
834
use of members after a dot without backticks, e.g. "foo.default".

include/swift/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,9 +1240,13 @@ class Parser {
12401240
ParserResult<GenericParamList> parseGenericParameters();
12411241
ParserResult<GenericParamList> parseGenericParameters(SourceLoc LAngleLoc);
12421242
ParserResult<GenericParamList> maybeParseGenericParams();
1243+
ParserStatus parseFreestandingGenericWhereClause(GenericParamList *&GPList);
1244+
12431245
ParserStatus parseGenericWhereClause(SourceLoc &WhereLoc,
12441246
SmallVectorImpl<RequirementRepr> &Requirements,
12451247
bool &FirstTypeInComplete);
1248+
1249+
12461250

12471251
//===--------------------------------------------------------------------===//
12481252
// Availability Specification Parsing

lib/Parse/ParseDecl.cpp

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2930,10 +2930,10 @@ ParserResult<IfConfigDecl> Parser::parseDeclIfConfig(ParseDeclOptions Flags) {
29302930
///
29312931
/// \verbatim
29322932
/// decl-typealias:
2933-
/// 'typealias' identifier generic-params? '=' type
2933+
/// 'typealias' identifier generic-params? '=' type requirement-clause?
29342934
/// \endverbatim
2935-
ParserResult<TypeDecl> Parser::parseDeclTypeAlias(Parser::ParseDeclOptions Flags,
2936-
DeclAttributes &Attributes) {
2935+
ParserResult<TypeDecl> Parser::
2936+
parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) {
29372937
ParserPosition startPosition = getParserPosition();
29382938
SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias);
29392939
Identifier Id;
@@ -2991,6 +2991,13 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(Parser::ParseDeclOptions Flags
29912991
if (UnderlyingTy.isNull())
29922992
return Status;
29932993

2994+
// Parse a 'where' clause if present, adding it to our GenericParamList.
2995+
if (Tok.is(tok::kw_where)) {
2996+
auto whereStatus = parseFreestandingGenericWhereClause(genericParams);
2997+
if (whereStatus.shouldStopParsing())
2998+
return whereStatus;
2999+
}
3000+
29943001
auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, Id, IdLoc,
29953002
UnderlyingTy.getPtrOrNull(),
29963003
genericParams, CurDeclContext);
@@ -4408,7 +4415,8 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD,
44084415
/// \verbatim
44094416
/// decl-func:
44104417
/// attribute-list? ('static' | 'class')? 'mutating'? 'func'
4411-
/// any-identifier generic-params? func-signature stmt-brace?
4418+
/// any-identifier generic-params? func-signature where-clause?
4419+
/// stmt-brace?
44124420
/// \endverbatim
44134421
///
44144422
/// \note The caller of this method must ensure that the next token is 'func'.
@@ -4557,6 +4565,13 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
45574565
return SignatureStatus;
45584566
}
45594567

4568+
// Parse a 'where' clause if present, adding it to our GenericParamList.
4569+
if (Tok.is(tok::kw_where)) {
4570+
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
4571+
if (whereStatus.shouldStopParsing())
4572+
return whereStatus;
4573+
}
4574+
45604575
// Protocol method arguments may not have default values.
45614576
if (Flags.contains(PD_InProtocol) && DefaultArgs.HasDefaultArgument) {
45624577
diagnose(FuncLoc, diag::protocol_method_argument_init);
@@ -4686,7 +4701,7 @@ bool Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) {
46864701
/// \verbatim
46874702
/// decl-enum:
46884703
/// 'enum' attribute-list identifier generic-params? inheritance?
4689-
/// '{' decl-enum-body '}'
4704+
/// where-clause? '{' decl-enum-body '}'
46904705
/// decl-enum-body:
46914706
/// decl*
46924707
/// \endverbatim
@@ -4729,6 +4744,14 @@ ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
47294744
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
47304745
UD->setInherited(Context.AllocateCopy(Inherited));
47314746
}
4747+
4748+
// Parse a 'where' clause if present, adding it to our GenericParamList.
4749+
if (Tok.is(tok::kw_where)) {
4750+
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
4751+
if (whereStatus.shouldStopParsing())
4752+
return whereStatus;
4753+
UD->setGenericParams(GenericParams);
4754+
}
47324755

47334756
SourceLoc LBLoc, RBLoc;
47344757
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_enum)) {
@@ -4966,7 +4989,7 @@ bool Parser::parseNominalDeclMembers(SourceLoc LBLoc, SourceLoc &RBLoc,
49664989
/// \verbatim
49674990
/// decl-struct:
49684991
/// 'struct' attribute-list identifier generic-params? inheritance?
4969-
/// '{' decl-struct-body '}
4992+
/// where-clause? '{' decl-struct-body '}
49704993
/// decl-struct-body:
49714994
/// decl*
49724995
/// \endverbatim
@@ -5012,6 +5035,14 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
50125035
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
50135036
SD->setInherited(Context.AllocateCopy(Inherited));
50145037
}
5038+
5039+
// Parse a 'where' clause if present, adding it to our GenericParamList.
5040+
if (Tok.is(tok::kw_where)) {
5041+
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
5042+
if (whereStatus.shouldStopParsing())
5043+
return whereStatus;
5044+
SD->setGenericParams(GenericParams);
5045+
}
50155046

50165047
SourceLoc LBLoc, RBLoc;
50175048
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_struct)) {
@@ -5047,7 +5078,7 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
50475078
/// \verbatim
50485079
/// decl-class:
50495080
/// 'class' attribute-list identifier generic-params? inheritance?
5050-
/// '{' decl-class-body '}
5081+
/// where-clause? '{' decl-class-body '}
50515082
/// decl-class-body:
50525083
/// decl*
50535084
/// \endverbatim
@@ -5093,6 +5124,14 @@ ParserResult<ClassDecl> Parser::parseDeclClass(SourceLoc ClassLoc,
50935124
CD->setInherited(Context.AllocateCopy(Inherited));
50945125
}
50955126

5127+
// Parse a 'where' clause if present, adding it to our GenericParamList.
5128+
if (Tok.is(tok::kw_where)) {
5129+
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
5130+
if (whereStatus.shouldStopParsing())
5131+
return whereStatus;
5132+
CD->setGenericParams(GenericParams);
5133+
}
5134+
50965135
SourceLoc LBLoc, RBLoc;
50975136
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_class)) {
50985137
LBLoc = PreviousLoc;
@@ -5376,6 +5415,13 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
53765415
Attributes.add(new (Context) RethrowsAttr(throwsLoc));
53775416
}
53785417

5418+
// Parse a 'where' clause if present, adding it to our GenericParamList.
5419+
if (Tok.is(tok::kw_where)) {
5420+
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
5421+
if (whereStatus.shouldStopParsing())
5422+
return whereStatus;
5423+
}
5424+
53795425
auto *SelfDecl = ParamDecl::createUnboundSelf(ConstructorLoc, CurDeclContext);
53805426

53815427
Scope S2(this, ScopeKind::ConstructorBody);

lib/Parse/ParseGeneric.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,44 @@ ParserStatus Parser::parseGenericWhereClause(
260260

261261
return Status;
262262
}
263+
264+
265+
/// Parse a free-standing where clause attached to a declaration, adding it to
266+
/// a generic parameter list that may (or may not) already exist.
267+
ParserStatus Parser::
268+
parseFreestandingGenericWhereClause(GenericParamList *&genericParams) {
269+
assert(Tok.is(tok::kw_where) && "Shouldn't call this without a where");
270+
271+
// Push the generic arguments back into a local scope so that references will
272+
// find them.
273+
Scope S(this, ScopeKind::Generics);
274+
275+
if (genericParams)
276+
for (auto pd : genericParams->getParams())
277+
addToScope(pd);
278+
279+
SmallVector<RequirementRepr, 4> Requirements;
280+
if (genericParams)
281+
Requirements.append(genericParams->getRequirements().begin(),
282+
genericParams->getRequirements().end());
283+
284+
SourceLoc WhereLoc;
285+
bool FirstTypeInComplete;
286+
auto result = parseGenericWhereClause(WhereLoc, Requirements,
287+
FirstTypeInComplete);
288+
if (result.shouldStopParsing() || Requirements.empty())
289+
return result;
290+
291+
if (!genericParams)
292+
genericParams = GenericParamList::create(Context, SourceLoc(),
293+
{}, WhereLoc, Requirements,
294+
SourceLoc());
295+
else
296+
genericParams = GenericParamList::create(Context,
297+
genericParams->getLAngleLoc(),
298+
genericParams->getParams(),
299+
WhereLoc, Requirements,
300+
genericParams->getRAngleLoc());
301+
return ParserStatus();
302+
}
303+

test/Generics/associated_self_constraints.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ protocol P {
6363
struct IP<T> : P {
6464
typealias A = T
6565

66-
init<O:P where O.A == IP.A>(x:O) {
66+
init<O:P>(x:O) where O.A == IP.A {
6767
_onNext = { (item: A) in x.onNext(item) }
6868
}
6969

test/Generics/function_defs.swift

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,8 @@ func testOrdered<T : Ordered>(_ x: T, y: Int) {
189189
//===----------------------------------------------------------------------===//
190190
// Requires clauses
191191
//===----------------------------------------------------------------------===//
192-
func conformanceViaRequires<T
193-
where T : EqualComparable, T : MethodLessComparable
194-
>(_ t1: T, t2: T) -> Bool {
192+
func conformanceViaRequires<T>(_ t1: T, t2: T) -> Bool
193+
where T : EqualComparable, T : MethodLessComparable {
195194
let b1 = t1.isEqual(t2)
196195
if b1 || t1.isLess(t2) {
197196
return true
@@ -208,7 +207,8 @@ protocol AcceptsAnElement {
208207
func accept(_ e : Element)
209208
}
210209

211-
func impliedSameType<T : GeneratesAnElement where T : AcceptsAnElement>(_ t: T) {
210+
func impliedSameType<T : GeneratesAnElement>(_ t: T)
211+
where T : AcceptsAnElement {
212212
t.accept(t.makeIterator())
213213
let e = t.makeIterator(), e2 = t.makeIterator()
214214
if e.isEqual(e2) || e.isLess(e2) {
@@ -226,10 +226,9 @@ protocol GeneratesAssoc2 {
226226
func get() -> Assoc2
227227
}
228228

229-
func simpleSameType
230-
<T : GeneratesAssoc1, U : GeneratesAssoc2 where T.Assoc1 == U.Assoc2>
231-
(_ t: T, u: U) -> Bool
232-
{
229+
func simpleSameType<T : GeneratesAssoc1, U : GeneratesAssoc2>
230+
(_ t: T, u: U) -> Bool
231+
where T.Assoc1 == U.Assoc2 {
233232
return t.get().isEqual(u.get()) || u.get().isLess(t.get())
234233
}
235234

@@ -244,9 +243,9 @@ protocol GeneratesMetaAssoc2 {
244243
}
245244

246245
func recursiveSameType
247-
<T : GeneratesMetaAssoc1, U : GeneratesMetaAssoc2, V : GeneratesAssoc1
248-
where T.MetaAssoc1 == V.Assoc1, V.Assoc1 == U.MetaAssoc2>
246+
<T : GeneratesMetaAssoc1, U : GeneratesMetaAssoc2, V : GeneratesAssoc1>
249247
(_ t: T, u: U)
248+
where T.MetaAssoc1 == V.Assoc1, V.Assoc1 == U.MetaAssoc2
250249
{
251250
t.get().accept(t.get().makeIterator())
252251
let e = t.get().makeIterator(), e2 = t.get().makeIterator()
@@ -265,12 +264,9 @@ protocol P2 {
265264
func getAssocP1() -> AssocP1
266265
}
267266

268-
func beginsWith2<
269-
E0: P1, E1: P1
270-
where
271-
E0.Element == E1.Element,
272-
E0.Element : EqualComparable
273-
>(_ e0: E0, _ e1: E1) -> Bool
267+
func beginsWith2<E0: P1, E1: P1>(_ e0: E0, _ e1: E1) -> Bool
268+
where E0.Element == E1.Element,
269+
E0.Element : EqualComparable
274270
{
275271
}
276272

test/Generics/generic_types.swift

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ struct formattedTestS<T : MyFormattedPrintable> {
6363
}
6464
}
6565

66-
struct GenericReq<
67-
T : IteratorProtocol, U : IteratorProtocol where T.Element == U.Element
68-
> {}
66+
struct GenericReq<T : IteratorProtocol, U : IteratorProtocol>
67+
where T.Element == U.Element {
68+
}
6969

7070
func getFirst<R : IteratorProtocol>(_ r: R) -> R.Element {
7171
var r = r
@@ -138,11 +138,8 @@ var d2 : Dictionary<String, Int>
138138
d1["hello"] = d2["world"]
139139
i = d2["blarg"]
140140

141-
struct RangeOfPrintables<
142-
R : Sequence
143-
where
144-
R.Iterator.Element : MyFormattedPrintable
145-
> {
141+
struct RangeOfPrintables<R : Sequence>
142+
where R.Iterator.Element : MyFormattedPrintable {
146143
var r : R
147144

148145
func format() -> String {
@@ -307,7 +304,7 @@ struct X4 : P, Q {
307304
typealias AssocQ = String
308305
}
309306

310-
struct X5<T, U where T: P, T: Q, T.AssocP == T.AssocQ> { } // expected-note{{requirement specified as 'T.AssocP' == 'T.AssocQ' [with T = X4]}}
307+
struct X5<T, U> where T: P, T: Q, T.AssocP == T.AssocQ { } // expected-note{{requirement specified as 'T.AssocP' == 'T.AssocQ' [with T = X4]}}
311308

312309
var y: X5<X4, Int> // expected-error{{'X5' requires the types 'AssocP' (aka 'Int') and 'AssocQ' (aka 'String') be equivalent}}
313310

@@ -334,4 +331,4 @@ struct UnsolvableInheritance2<T : U.A, U : T.A> {}
334331
// expected-error@-1 {{inheritance from non-protocol, non-class type 'U.A'}}
335332
// expected-error@-2 {{inheritance from non-protocol, non-class type 'T.A'}}
336333

337-
enum X7<T where X7.X : G> { case X } // expected-error{{'X' is not a member type of 'X7<T>'}}
334+
enum X7<T> where X7.X : G { case X } // expected-error{{'X' is not a member type of 'X7<T>'}}

test/IRGen/mixed_objc_native_protocol_constraints.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55

66
protocol Fooable { func foo() }
77

8-
class A<B: Fooable where B: AnyObject> {
8+
class A<B: Fooable> where B: AnyObject{
99
}

test/decl/nested.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ class OuterNonGenericClass {
7878
init(t: T) { super.init(); self.t = t }
7979
}
8080

81-
class InnerGenericClass<U where U : Racoon, U.Stripes == T> : OuterNonGenericClass { // expected-error {{type 'InnerGenericClass' nested in generic function}}
81+
class InnerGenericClass<U> : OuterNonGenericClass // expected-error {{type 'InnerGenericClass' nested in generic function}}
82+
where U : Racoon, U.Stripes == T {
8283
let t: T
8384

8485
init(t: T) { super.init(); self.t = t }
@@ -151,7 +152,8 @@ class OuterGenericClass<T> {
151152
init(t: T) { super.init(); self.t = t }
152153
}
153154

154-
class InnerGenericClass<U where U : Racoon, U.Stripes == T> : OuterGenericClass<U> { // expected-error {{type 'InnerGenericClass' nested in generic function}}
155+
class InnerGenericClass<U> : OuterGenericClass<U> // expected-error {{type 'InnerGenericClass' nested in generic function}}
156+
where U : Racoon, U.Stripes == T {
155157
let t: T
156158

157159
init(t: T) { super.init(); self.t = t }

test/decl/typealias/typealias.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ typealias BadC<T,T> = MyType<String, T> // expected-error {{definition conflict
4848

4949
typealias Tuple2<T1, T2> = (T1, T2)
5050

51+
typealias Tuple3<T1> = (T1, T1) where T1 : Hashable
52+
53+
5154
let _ : Tuple2<Int, String> = (1, "foo")
5255
let _ : Tuple2 = (1, "foo")
5356
let _ : Tuple2<Int, String> = ("bar", // expected-error {{cannot convert value of type 'String' to specified type 'Int'}}

0 commit comments

Comments
 (0)