Skip to content

Commit 6532b23

Browse files
authored
Merge pull request #69591 from kavon/noncopyable-generics-pt3
[NoncopyableGenerics] Basic end-to-end testing (without stdlib).
2 parents edb5d6a + dc9ca0a commit 6532b23

16 files changed

+368
-195
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_BASIC_LANGOPTIONS_H
2020

2121
#include "swift/Basic/Feature.h"
22+
#include "swift/Basic/FixedBitSet.h"
2223
#include "swift/Basic/FunctionBodySkipping.h"
2324
#include "swift/Basic/LLVM.h"
2425
#include "swift/Basic/Version.h"
@@ -28,7 +29,6 @@
2829
#include "llvm/ADT/Hashing.h"
2930
#include "llvm/ADT/None.h"
3031
#include "llvm/ADT/Optional.h"
31-
#include "llvm/ADT/SmallSet.h"
3232
#include "llvm/ADT/SmallString.h"
3333
#include "llvm/ADT/SmallVector.h"
3434
#include "llvm/ADT/StringRef.h"
@@ -429,7 +429,7 @@ namespace swift {
429429
bool EnableNewOperatorLookup = false;
430430

431431
/// The set of features that have been enabled.
432-
llvm::SmallSet<Feature, 2> Features;
432+
FixedBitSet<numFeatures(), Feature> Features;
433433

434434
/// Temporary flag to support LLDB's transition to using \c Features.
435435
bool EnableBareSlashRegexLiterals = false;

include/swift/SIL/SILType.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -862,10 +862,6 @@ class SILType {
862862
return getSILBoxFieldType(fn).isMoveOnly();
863863
}
864864

865-
bool isBoxedNonCopyableType(const SILFunction &fn) const {
866-
return isBoxedNonCopyableType(&fn);
867-
}
868-
869865
bool isBoxedMoveOnlyWrappedType(const SILFunction *fn) const {
870866
if (!this->is<SILBoxType>())
871867
return false;

lib/IRGen/GenReflection.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ getTypeRefImpl(IRGenModule &IGM,
396396
useFlatUnique = true;
397397
break;
398398

399-
case MangledTypeRefRole::FieldMetadata:
399+
case MangledTypeRefRole::FieldMetadata: {
400400
// We want to keep fields of noncopyable type from being exposed to
401401
// in-process runtime reflection libraries in older Swift runtimes, since
402402
// they more than likely assume they can copy field values, and the language
@@ -405,11 +405,16 @@ getTypeRefImpl(IRGenModule &IGM,
405405
// noncopyable, use a function to emit the type ref which will look for a
406406
// signal from future runtimes whether they support noncopyable types before
407407
// exposing their metadata to them.
408-
if (type->isNoncopyable()) {
408+
Type contextualTy = type;
409+
if (sig)
410+
contextualTy = sig.getGenericEnvironment()->mapTypeIntoContext(type);
411+
412+
if (contextualTy->isNoncopyable()) {
409413
IGM.IRGen.noteUseOfTypeMetadata(type);
410414
return getTypeRefByFunction(IGM, sig, type);
411415
}
412-
LLVM_FALLTHROUGH;
416+
}
417+
LLVM_FALLTHROUGH;
413418

414419
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
415420
case MangledTypeRefRole::Metadata:

lib/SIL/IR/SILInstructions.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,9 @@ AllocBoxInst::AllocBoxInst(SILDebugLocation Loc, CanSILBoxType BoxType,
387387
sharedUInt8().AllocBoxInst.reflection = reflection;
388388

389389
// If we have a noncopyable type, always set uses mvoeable value debug info.
390-
usesMoveableValueDebugInfo |=
391-
BoxType->getLayout()->getFields()[0].getObjectType().isMoveOnly();
390+
auto fieldTy = getSILBoxFieldType(F.getTypeExpansionContext(), BoxType,
391+
F.getModule().Types, 0);
392+
usesMoveableValueDebugInfo |= fieldTy.isMoveOnly();
392393

393394
sharedUInt8().AllocBoxInst.usesMoveableValueDebugInfo =
394395
usesMoveableValueDebugInfo;

lib/SIL/IR/SILType.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,10 +1044,20 @@ SILType::getSingletonAggregateFieldType(SILModule &M,
10441044
}
10451045

10461046
bool SILType::isMoveOnly() const {
1047-
// Nominal types are move-only if declared as such.
1048-
if (getASTType()->isNoncopyable())
1047+
// Legacy check.
1048+
if (!getASTContext().LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
1049+
return getASTType()->isNoncopyable() || isMoveOnlyWrapped();
1050+
}
1051+
1052+
// Anything within the move-only wrapper is move-only.
1053+
if (isMoveOnlyWrapped())
10491054
return true;
10501055

1056+
auto ty = getASTType();
1057+
1058+
// All kinds of references are copyable.
1059+
if (isa<ReferenceStorageType>(ty))
1060+
return false;
10511061

10521062
// TODO: Nonescaping closures ought to be treated as move-only in SIL.
10531063
// They aren't marked move-only now, because the necessary move-only passes
@@ -1060,7 +1070,19 @@ bool SILType::isMoveOnly() const {
10601070
return fnTy->isTrivialNoEscape();
10611071
}
10621072
*/
1063-
return isMoveOnlyWrapped();
1073+
if (isa<SILFunctionType>(ty))
1074+
return false;
1075+
1076+
// Treat all other SIL-specific types as Copyable.
1077+
if (isa<SILBlockStorageType,
1078+
SILBoxType,
1079+
SILPackType,
1080+
SILTokenType>(ty)) {
1081+
return false;
1082+
}
1083+
1084+
// Finally, for other ordinary types, ask the AST type.
1085+
return ty->isNoncopyable();
10641086
}
10651087

10661088

lib/SILOptimizer/Transforms/AllocBoxToStack.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,7 @@ specializeApplySite(SILOptFunctionBuilder &FuncBuilder, ApplySite Apply,
10621062
// boxes, convert them from having escaping to having non-escaping
10631063
// semantics.
10641064
for (unsigned index : PromotedCalleeArgIndices) {
1065-
if (F->getArgument(index)->getType().isBoxedNonCopyableType(*F)) {
1065+
if (F->getArgument(index)->getType().isBoxedNonCopyableType(F)) {
10661066
auto boxType = F->getArgument(index)->getType().castTo<SILBoxType>();
10671067
bool isMutable = boxType->getLayout()->getFields()[0].isMutable();
10681068
auto checkKind = isMutable ? MarkUnresolvedNonCopyableValueInst::

lib/Sema/TypeCheckDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,9 @@ bool HasNoncopyableAnnotationRequest::evaluate(Evaluator &evaluator, TypeDecl *d
944944

945945
// Handle the legacy '@_moveOnly' attribute
946946
if (decl->getAttrs().hasAttribute<MoveOnlyAttr>()) {
947-
assert(isa<StructDecl>(decl) || isa<EnumDecl>(decl));
947+
assert(isa<StructDecl>(decl) || isa<EnumDecl>(decl)
948+
|| (ctx.LangOpts.hasFeature(Feature::MoveOnlyClasses)
949+
&& isa<ClassDecl>(decl)));
948950
return true;
949951
}
950952

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all -enable-experimental-feature NoncopyableGenerics)
2+
// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all -enable-experimental-feature NoncopyableGenerics)
3+
4+
// REQUIRES: executable_test
5+
// REQUIRES: asserts
6+
7+
// Needed due to limitations of autoclosures and noncopyable types.
8+
func eagerAssert(_ b: Bool, _ line: Int = #line) {
9+
guard b else { fatalError("assertion failure on line \(line)") }
10+
}
11+
12+
///---------------------
13+
/// MARK: a Swift x Haskell limited-edition stdlib
14+
/// ---------------------
15+
16+
17+
18+
/// MARK: Ord aka 'Comparable'
19+
protocol Ord: ~Copyable {
20+
func compare(_ other: borrowing Self) -> Ordering
21+
}
22+
23+
enum Ordering {
24+
case LT
25+
case EQ
26+
case GT
27+
28+
static func compare<T: Comparable>(_ a: borrowing T, _ b: borrowing T) -> Ordering {
29+
if (a < b) { return .LT }
30+
if (a > b) { return .GT }
31+
eagerAssert(a == b)
32+
return .EQ
33+
}
34+
}
35+
36+
extension Ord {
37+
static func <(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
38+
return a.compare(b) == .LT
39+
}
40+
static func <=(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
41+
return !(a > b)
42+
}
43+
static func >(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
44+
return a.compare(b) == .GT
45+
}
46+
static func >=(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
47+
return !(a < b)
48+
}
49+
static func ==(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
50+
a.compare(b) == .EQ
51+
}
52+
static func !=(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
53+
!(a == b)
54+
}
55+
}
56+
57+
/// MARK: Maybe aka 'Optional'
58+
enum Maybe<Val: ~Copyable>: ~Copyable {
59+
case just(Val)
60+
case none
61+
62+
// NOTE: a 'consuming' version of the unfortunately 'borrowing' map from the stdlib.
63+
consuming func consumingMap<U: ~Copyable>(_ fn: (consuming Val) throws -> U) rethrows -> Maybe<U> {
64+
// rdar://117638878 (MoveOnlyAddressChecker crashes with generic associated value in enum)
65+
fatalError("need to fix rdar://117638878")
66+
// return switch consume self {
67+
// case let .just(val): .just(try fn(val))
68+
// case .none: .none
69+
// }
70+
}
71+
}
72+
73+
// NOTE: temporary
74+
extension Maybe: Copyable where Val: Copyable {}
75+
76+
77+
/// MARK: beginning of tests
78+
79+
struct FileDescriptor: ~Copyable, Ord {
80+
let id: Int
81+
82+
func compare(_ other: borrowing FileDescriptor) -> Ordering {
83+
return .compare(id, other.id)
84+
}
85+
86+
deinit { print("calling deinit!") }
87+
}
88+
89+
class Shared<T: ~Copyable> {
90+
let value: T
91+
init(_ val: consuming T) { self.value = val }
92+
func borrow<V>(_ f: (borrowing T) throws -> V) rethrows -> V {
93+
return try f(value)
94+
}
95+
}
96+
97+
defer { testOrd() }
98+
func testOrd() {
99+
let stderr = Shared(FileDescriptor(id: 1))
100+
let stdout = Shared(FileDescriptor(id: 0))
101+
stdout.borrow { out in
102+
stderr.borrow { err in
103+
eagerAssert(err > out)
104+
eagerAssert(out < err)
105+
eagerAssert(out != err)
106+
}
107+
}
108+
}
109+
110+
defer { testMaybe() }
111+
func testMaybe() {
112+
let mayb = Maybe.just(FileDescriptor(id: 0));
113+
switch consume mayb {
114+
case let .just(fd): eagerAssert(fd.id == 0)
115+
case .none: eagerAssert(false)
116+
}
117+
}

0 commit comments

Comments
 (0)