Skip to content

Commit 7b9e5de

Browse files
joewillsherDougGregor
authored andcommitted
[SE-0095] simplifyTypeExpr for composition expressions
Also adds: - Any is caught before doing an unconstrained lookup, and the protocol<> type is emitted - composition expressions can be handled by `PreCheckExpression::simplifyTypeExpr` to so you can do lookups like (P & Q).self - Fixits corrected & new tests added - Typeref lowering cases should have been optional - This fixes a failing test case.
1 parent a6dad00 commit 7b9e5de

23 files changed

+2088
-81
lines changed

CHANGELOG.md

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

6+
* [SE-0095](https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md):
7+
The `protocol<...>` composition construct has been removed. In its place, an infix type operator `&` has been introduced.
8+
9+
```swift
10+
let a: Foo & Bar
11+
let b = value as? A & B & C
12+
func foo<T : Foo & Bar>(x: T) { }
13+
func bar(x: Foo & Bar) { }
14+
typealias G = GenericStruct<Foo & Bar>
15+
```
16+
17+
The empty protocol composition, the `Any` type, was previously defined as being `protocol<>`. This has been removed from the standard library and `Any` is now a keyword with the same behaviour.
18+
619
* [SE-0091](https://github.com/apple/swift-evolution/blob/master/proposals/0091-improving-operators-in-protocols.md):
720
Operators can now be defined within types or extensions thereof. For example:
821

@@ -93,6 +106,7 @@ Swift 3.0
93106
Similarly, the new `RecoverableError` and `CustomNSError` protocols
94107
allow additional control over the handling of the error.
95108

109+
96110
* [SE-0060](https://github.com/apple/swift-evolution/blob/master/proposals/0060-defaulted-parameter-order.md):
97111
Function parameters with default arguments must now be specified in
98112
declaration order. A call site must always supply the arguments it provides

include/swift/AST/ASTContext.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,6 @@ class ASTContext {
443443
/// Retrieve the declaration of Swift.Void.
444444
TypeAliasDecl *getVoidDecl() const;
445445

446-
TypeAliasDecl *getAnyDecl() const;
447-
448446
/// Retrieve the declaration of ObjectiveC.ObjCBool.
449447
StructDecl *getObjCBoolDecl();
450448

include/swift/AST/DiagnosticsParse.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ ERROR(disallowed_protocol_composition,PointsToFirstBadToken,
656656
"protocol composition is neither allowed nor needed here", ())
657657

658658
WARNING(deprecated_protocol_composition,PointsToFirstBadToken,
659-
"'protocol<...>' composition syntax is deprecated; use infix '&' instead", ())
659+
"'protocol<...>' composition syntax is deprecated; join the protocols using '&'", ())
660660
WARNING(deprecated_any_composition,PointsToFirstBadToken,
661661
"'protocol<>' syntax is deprecated; use 'Any' instead", ())
662662

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ ERROR(reserved_member_name,none,
517517
ERROR(invalid_redecl,none,"invalid redeclaration of %0", (DeclName))
518518
NOTE(invalid_redecl_prev,none,
519519
"%0 previously declared here", (DeclName))
520-
ERROR(invalid_redecl_any,none,"invalid redeclaration of 'Any'; cannot override type keyword", ())
520+
ERROR(invalid_redecl_any,none,"invalid redeclaration of 'Any'; cannot overload type keyword", ())
521521

522522
ERROR(ambiguous_type_base,none,
523523
"%0 is ambiguous for type lookup in this context", (Identifier))

lib/AST/ASTContext.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -802,24 +802,6 @@ TypeAliasDecl *ASTContext::getVoidDecl() const {
802802
return Impl.VoidDecl;
803803
}
804804

805-
TypeAliasDecl *ASTContext::getAnyDecl() const {
806-
if (Impl.VoidDecl) {
807-
return Impl.VoidDecl;
808-
}
809-
810-
// Go find 'Void' in the Swift module.
811-
SmallVector<ValueDecl *, 1> results;
812-
lookupInSwiftModule("Any", results);
813-
for (auto result : results) {
814-
if (auto typeAlias = dyn_cast<TypeAliasDecl>(result)) {
815-
Impl.VoidDecl = typeAlias;
816-
return typeAlias;
817-
}
818-
}
819-
820-
return Impl.VoidDecl;
821-
}
822-
823805
StructDecl *ASTContext::getObjCBoolDecl() {
824806
if (!Impl.ObjCBoolDecl) {
825807
SmallVector<ValueDecl *, 1> results;

lib/Parse/ParseDecl.cpp

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2435,41 +2435,36 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
24352435

24362436
auto usesDeprecatedCompositionSyntax = Tok.is(tok::kw_protocol) && startsWithLess(peekToken());
24372437

2438-
auto compositionResult = parseTypeIdentifierOrTypeComposition();
2439-
Status |= compositionResult;
2438+
auto ParsedTypeResult = parseTypeIdentifierOrTypeComposition();
2439+
Status |= ParsedTypeResult;
24402440

2441-
if (auto composition = dyn_cast_or_null<ProtocolCompositionTypeRepr>(compositionResult.getPtrOrNull())) {
2441+
// cannot inherit from composition
2442+
if (auto Composition = dyn_cast_or_null<ProtocolCompositionTypeRepr>(ParsedTypeResult.getPtrOrNull())) {
24422443
// Record the protocols inside the composition.
2443-
Inherited.append(composition->getProtocols().begin(),
2444-
composition->getProtocols().end());
2444+
Inherited.append(Composition->getProtocols().begin(),
2445+
Composition->getProtocols().end());
24452446
if (usesDeprecatedCompositionSyntax) {
24462447
// Provide fixits to remove the composition, leaving the types intact.
2447-
auto compositionRange = composition->getCompositionRange();
2448-
diagnose(composition->getStartLoc(),
2448+
auto compositionRange = Composition->getCompositionRange();
2449+
diagnose(Composition->getStartLoc(),
24492450
diag::disallowed_protocol_composition)
2450-
.highlight({composition->getStartLoc(), compositionRange.End})
2451-
.fixItRemove({composition->getStartLoc(), compositionRange.Start})
2451+
.highlight({Composition->getStartLoc(), compositionRange.End})
2452+
.fixItRemove({Composition->getStartLoc(), compositionRange.Start})
24522453
.fixItRemove(startsWithGreater(L->getTokenAt(compositionRange.End))
24532454
? compositionRange.End
24542455
: SourceLoc());
24552456
} else {
2456-
diagnose(composition->getStartLoc(),
2457+
diagnose(Composition->getStartLoc(),
24572458
diag::disallowed_protocol_composition)
2458-
.highlight(composition->getCompositionRange());
2459+
.highlight(Composition->getCompositionRange());
24592460
// TODO: Decompose 'A & B & C' list to 'A, B, C'
24602461
}
2461-
continue;
24622462
} else {
2463-
// Parse the inherited type (which must be a protocol).
2464-
ParserResult<TypeRepr> Ty = compositionResult;
2465-
Status |= Ty;
2466-
// Record the type.
2467-
if (Ty.isNonNull())
2468-
Inherited.push_back(Ty.get());
2463+
// Record the type if its a single type.
2464+
if (ParsedTypeResult.isNonNull())
2465+
Inherited.push_back(ParsedTypeResult.get());
24692466
}
24702467

2471-
2472-
24732468
// Check for a ',', which indicates that there are more protocols coming.
24742469
} while (consumeIf(tok::comma, prevComma));
24752470

lib/Parse/ParseType.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -419,8 +419,7 @@ ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() {
419419
// Check for empty protocol composition.
420420
if (startsWithGreater(Tok)) {
421421
SourceLoc RAngleLoc = consumeStartingGreater();
422-
423-
auto AnyRange = SourceRange(LAngleLoc, RAngleLoc);
422+
auto AnyRange = SourceRange(ProtocolLoc, RAngleLoc);
424423

425424
// warn that 'protocol<>' is depreacted and offer to
426425
// repalace with the 'Any' keyword
@@ -470,10 +469,9 @@ ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() {
470469

471470
Diag.highlight({ProtocolLoc, RAngleLoc});
472471
for (auto Comma : Commas) // remove commas and '<'
473-
Diag.fixItReplace(Comma, " & ");
474-
Diag // remove 'protocol<'
475-
.fixItRemove(ProtocolLoc)
476-
.fixItRemove(LAngleLoc)
472+
Diag.fixItReplace(Comma, " &");
473+
Diag
474+
.fixItRemove({ProtocolLoc, LAngleLoc}) // remove 'protocol<'
477475
.fixItRemove(RAngleLoc); // remove '>'
478476

479477
return makeParserResult(Status, composition);
@@ -501,7 +499,7 @@ ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() {
501499
Protocols.push_back(Protocol.get());
502500
};
503501

504-
return makeParserResult(Status, ProtocolCompositionTypeRepr::create(Context, Protocols, FirstTypeLoc, {FirstTypeLoc, Tok.getLoc()}));
502+
return makeParserResult(Status, ProtocolCompositionTypeRepr::create(Context, Protocols, FirstTypeLoc, {FirstTypeLoc, PreviousLoc}));
505503
}
506504
}
507505

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,13 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) {
435435
DeclName Name = UDRE->getName();
436436
SourceLoc Loc = UDRE->getLoc();
437437

438+
// 'Any' is the empty protocol composition; resolve it before doing an
439+
// unqualified lookup
440+
if (Name.getBaseName() == Context.Id_Any) {
441+
auto *TypeRepr = new (Context) ProtocolCompositionTypeRepr(ArrayRef<IdentTypeRepr *>(), Loc, UDRE->getSourceRange());
442+
return new (Context) TypeExpr(TypeLoc(TypeRepr));
443+
}
444+
438445
// Perform standard value name lookup.
439446
NameLookupOptions LookupOptions = defaultUnqualifiedLookupOptions;
440447
if (isa<AbstractFunctionDecl>(DC))
@@ -1126,7 +1133,49 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) {
11261133
ResultTypeRepr);
11271134
return new (TC.Context) TypeExpr(TypeLoc(NewTypeRepr, Type()));
11281135
}
1129-
1136+
1137+
// Fold 'P & Q' into a composition type
1138+
if (auto *binaryExpr = dyn_cast<BinaryExpr>(E))
1139+
if (auto d = dyn_cast<OverloadedDeclRefExpr>(binaryExpr->getFn()))
1140+
for (auto decl : d->getDecls()) {
1141+
// for a composition
1142+
if (decl->getNameStr() == "&") {
1143+
// The protocols we are composing
1144+
SmallVector<IdentTypeRepr *, 4> Protocols;
1145+
1146+
auto lhsExpr = binaryExpr->getArg()->getElement(0);
1147+
if (auto *lhs = dyn_cast_or_null<TypeExpr>(lhsExpr)) {
1148+
if (auto repr = dyn_cast<IdentTypeRepr>(lhs->getTypeRepr()))
1149+
Protocols.push_back(repr);
1150+
}
1151+
// if the lhs is another binary expression, we have a multi element composition:
1152+
// 'A & B & C' is parsed as ((A & B) & C), so we get the protocols from the lhs here
1153+
else if (isa<BinaryExpr>(lhsExpr)) {
1154+
if (auto *expr = simplifyTypeExpr(lhsExpr)) {
1155+
if (auto* repr = dyn_cast<ProtocolCompositionTypeRepr>(expr->getTypeRepr()))
1156+
for (auto proto : repr->getProtocols())
1157+
Protocols.push_back(proto);
1158+
} else {
1159+
return nullptr;
1160+
}
1161+
} else {
1162+
return nullptr;
1163+
}
1164+
// add the rhs
1165+
auto rhs = dyn_cast_or_null<TypeExpr>(binaryExpr->getArg()->getElement(1));
1166+
if (!rhs) return nullptr;
1167+
1168+
if (auto repr = dyn_cast<IdentTypeRepr>(rhs->getTypeRepr()))
1169+
Protocols.push_back(repr);
1170+
1171+
auto CompositionRepr =
1172+
new (TC.Context) ProtocolCompositionTypeRepr(TC.Context.AllocateCopy(Protocols),
1173+
binaryExpr->getLoc(),
1174+
binaryExpr->getSourceRange());
1175+
return new (TC.Context) TypeExpr(TypeLoc(CompositionRepr, Type()));
1176+
}
1177+
}
1178+
11301179
return nullptr;
11311180
}
11321181

lib/Sema/TypeCheckDecl.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -868,13 +868,12 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
868868
if (!currentFile || currentDC->isLocalContext())
869869
return;
870870

871-
// Cannot define a global type called 'Any'
872-
if (current->getFullName() == tc.Context.getIdentifier("Any")) {
873-
// TODO: Diagnose this as an error; current workaround needs this capability though
874-
// tc.diagnose(current, diag::invalid_redecl_any);
875-
// return;
871+
// Cannot define a type called 'Any'
872+
if (current->getFullName() == tc.Context.Id_Any) {
873+
tc.diagnose(current, diag::invalid_redecl_any);
874+
return;
876875
}
877-
876+
878877
ReferencedNameTracker *tracker = currentFile->getReferencedNameTracker();
879878
bool isCascading = true;
880879
if (current->hasAccessibility())

lib/Sema/TypeCheckType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC,
824824

825825
// if it is an 'Any' type, return the unbounded composition type
826826
} else if (comp->getIdentifier() == TC.Context.Id_Any) {
827-
return ProtocolCompositionType::get(TC.Context, ArrayRef<Type>());
827+
return TC.Context.TheAnyType;
828828
}
829829

830830
// Resolve the first component, which is the only one that requires

stdlib/public/core/Policy.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ public typealias _MaxBuiltinFloatType = Builtin.FPIEEE64
9898
// Standard protocols
9999
//===----------------------------------------------------------------------===//
100100

101-
public typealias Any = protocol<>
102-
103101
#if _runtime(_ObjC)
104102
/// The protocol to which all classes implicitly conform.
105103
///

test/1_stdlib/TypeName.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ TypeNameTests.test("Prints") {
5353
expectEqual("protocol<main.P, main.P2>",
5454
_typeName(PP2.self))
5555
expectEqual("protocol<>", _typeName(Any.self))
56+
expectEqual("protocol<main.P, main.P2>", _typeName((P & P2).self))
5657

5758
typealias F = () -> ()
5859
typealias F2 = () -> () -> ()
@@ -61,7 +62,8 @@ TypeNameTests.test("Prints") {
6162
expectEqual("(()) -> ()", _typeName(F.self))
6263
expectEqual("(()) -> (()) -> ()", _typeName(F2.self))
6364
expectEqual("(((()) -> ())) -> ()", _typeName(F3.self))
64-
65+
expectEqual("(()) -> ()", _typeName((() -> ()).self))
66+
6567
#if _runtime(_ObjC)
6668
typealias B = @convention(block) () -> ()
6769
typealias B2 = () -> @convention(block) () -> ()
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-swift-frontend %clang-importer-sdk -parse %s -verify
2+
3+
// REQUIRES: objc_interop
4+
5+
import Foundation
6+
7+
enum FooError: HairyErrorProtocol, Runcible {
8+
case A
9+
10+
var hairiness: Int { return 0 }
11+
12+
func runce() {}
13+
}
14+
15+
protocol HairyErrorProtocol : ErrorProtocol {
16+
var hairiness: Int { get }
17+
}
18+
19+
protocol Runcible {
20+
func runce()
21+
}
22+
23+
let foo = FooError.A
24+
let error: ErrorProtocol = foo
25+
let subError: HairyErrorProtocol = foo
26+
let compo: HairyErrorProtocol & Runcible = foo
27+
28+
// ErrorProtocol-conforming concrete or existential types can be coerced explicitly
29+
// to NSError.
30+
let ns1 = foo as NSError
31+
let ns2 = error as NSError
32+
let ns3 = subError as NSError
33+
var ns4 = compo as NSError
34+
35+
// NSError conversion must be explicit.
36+
// TODO: fixit to insert 'as NSError'
37+
ns4 = compo // expected-error{{cannot assign value of type 'protocol<HairyErrorProtocol, Runcible>' to type 'NSError'}}
38+
39+
let e1 = ns1 as? FooError
40+
let e1fix = ns1 as FooError // expected-error{{did you mean to use 'as!'}} {{17-19=as!}}
41+
42+
let esub = ns1 as ErrorProtocol
43+
let esub2 = ns1 as? ErrorProtocol // expected-warning{{conditional cast from 'NSError' to 'ErrorProtocol' always succeeds}}

test/Parse/recovery.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ struct ErrorTypeInVarDecl7 {
281281
}
282282

283283
struct ErrorTypeInVarDecl8 {
284-
var v1 : protocol<FooProtocol // expected-error {{expected '>' to complete protocol composition type}} expected-note {{to match this opening '<'}} expected-warning{{'protocol<...>' composition syntax is deprecated; use infix '&' instead}}
284+
var v1 : protocol<FooProtocol // expected-error {{expected '>' to complete protocol composition type}} expected-note {{to match this opening '<'}} expected-warning{{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}}
285285
var v2 : Int
286286
}
287287

@@ -291,25 +291,25 @@ struct ErrorTypeInVarDecl9 {
291291
}
292292

293293
struct ErrorTypeInVarDecl10 {
294-
var v1 : protocol<FooProtocol // expected-error {{expected '>' to complete protocol composition type}} expected-note {{to match this opening '<'}} expected-warning {{'protocol<...>' composition syntax is deprecated; use infix '&' instead}}
294+
var v1 : protocol<FooProtocol // expected-error {{expected '>' to complete protocol composition type}} expected-note {{to match this opening '<'}} expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}}
295295
var v2 : Int
296296
}
297297

298298
struct ErrorTypeInVarDecl11 {
299-
var v1 : protocol<FooProtocol, // expected-error {{expected identifier for type name}} expected-warning {{'protocol<...>' composition syntax is deprecated; use infix '&' instead}}
299+
var v1 : protocol<FooProtocol, // expected-error {{expected identifier for type name}} expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}}
300300
var v2 : Int
301301
}
302302

303303
func ErrorTypeInPattern1(_: protocol<) { } // expected-error {{expected identifier for type name}}
304-
// expected-warning @-1 {{'protocol<...>' composition syntax is deprecated; use infix '&' instead}}
305-
func ErrorTypeInPattern2(_: protocol<F) { } // expected-warning {{'protocol<...>' composition syntax is deprecated; use infix '&' instead}}
304+
// expected-warning @-1 {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}}
305+
func ErrorTypeInPattern2(_: protocol<F) { } // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}}
306306
// expected-error@-1 {{expected '>' to complete protocol composition type}}
307307
// expected-note@-2 {{to match this opening '<'}}
308308
// expected-error@-3 {{use of undeclared type 'F'}}
309309

310310
func ErrorTypeInPattern3(_: protocol<F,) { } // expected-error {{expected identifier for type name}}
311311
// expected-error@-1 {{use of undeclared type 'F'}}
312-
// expected-warning@-2 {{'protocol<...>' composition syntax is deprecated; use infix '&' instead}}
312+
// expected-warning@-2 {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}}
313313

314314
struct ErrorTypeInVarDecl12 {
315315
var v1 : FooProtocol & // expected-error{{expected identifier for type name}}

0 commit comments

Comments
 (0)