Skip to content

Commit 34684c1

Browse files
authored
Merge pull request #65912 from kavon/5.9-noncopyable-fixes
[5.9🍒] Batch of small noncopyable type fixes
2 parents 6923717 + b206f34 commit 34684c1

File tree

9 files changed

+106
-28
lines changed

9 files changed

+106
-28
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7138,6 +7138,8 @@ ERROR(moveonly_cannot_conform_to_type, none,
71387138
(DescriptiveDeclKind, DeclName, Type))
71397139
ERROR(moveonly_parameter_missing_ownership, none,
71407140
"noncopyable parameter must specify its ownership", ())
7141+
ERROR(moveonly_parameter_subscript_unsupported, none,
7142+
"subscripts cannot have noncopyable parameters yet", ())
71417143
NOTE(moveonly_parameter_ownership_suggestion, none,
71427144
"add '%0' %1", (StringRef, StringRef))
71437145
ERROR(ownership_specifier_copyable,none,

lib/AST/Type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ bool TypeBase::isMarkerExistential() {
189189
}
190190

191191
bool TypeBase::isPureMoveOnly() {
192-
if (auto *nom = getNominalOrBoundGenericNominal())
192+
if (auto *nom = getAnyNominal())
193193
return nom->isMoveOnly();
194194

195195
// if any components of the tuple are move-only, then the tuple is move-only.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -912,8 +912,9 @@ IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
912912
}
913913

914914
bool IsMoveOnlyRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
915-
// For now only do this for nominal type decls.
916-
if (isa<NominalTypeDecl>(decl)) {
915+
// TODO: isPureMoveOnly and isMoveOnly and other checks are all spread out
916+
// and need to be merged together.
917+
if (isa<ClassDecl>(decl) || isa<StructDecl>(decl) || isa<EnumDecl>(decl)) {
917918
if (decl->getAttrs().hasAttribute<MoveOnlyAttr>()) {
918919
if (!decl->getASTContext().supportsMoveOnlyTypes())
919920
decl->diagnose(diag::moveOnly_requires_lexical_lifetimes);

lib/Sema/TypeCheckStmt.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,7 +1262,8 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
12621262
// check the kind of type this discard statement appears within.
12631263
if (!diagnosed) {
12641264
auto *nominalDecl = fn->getDeclContext()->getSelfNominalTypeDecl();
1265-
Type nominalType = nominalDecl->getDeclaredType();
1265+
Type nominalType =
1266+
fn->mapTypeIntoContext(nominalDecl->getDeclaredInterfaceType());
12661267

12671268
// must be noncopyable
12681269
if (!nominalType->isPureMoveOnly()) {
@@ -1288,17 +1289,16 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
12881289
// if the modules differ, so that you can discard a @frozen type from a
12891290
// resilient module. But for now the proposal simply says that it has to
12901291
// be the same module, which is probably better for everyone.
1291-
auto *typeDecl = nominalType->getAnyNominal();
12921292
auto *fnModule = fn->getModuleContext();
1293-
auto *typeModule = typeDecl->getModuleContext();
1293+
auto *typeModule = nominalDecl->getModuleContext();
12941294
if (fnModule != typeModule) {
12951295
ctx.Diags.diagnose(DS->getDiscardLoc(), diag::discard_wrong_module,
12961296
nominalType);
12971297
diagnosed = true;
12981298
} else {
12991299
assert(
1300-
!typeDecl->isResilient(fnModule, ResilienceExpansion::Maximal) &&
1301-
"trying to discard a type resilient to us!");
1300+
!nominalDecl->isResilient(fnModule, ResilienceExpansion::Maximal)
1301+
&& "trying to discard a type resilient to us!");
13021302
}
13031303
}
13041304
}
@@ -1314,13 +1314,14 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
13141314
if (!diagnosed) {
13151315
bool isSelf = false;
13161316
auto *checkE = DS->getSubExpr();
1317+
assert(fn->getImplicitSelfDecl() && "no self?");
13171318

13181319
// Look through a load. Only expected if we're in an init.
13191320
if (auto *load = dyn_cast<LoadExpr>(checkE))
13201321
checkE = load->getSubExpr();
13211322

13221323
if (auto DRE = dyn_cast<DeclRefExpr>(checkE))
1323-
isSelf = DRE->getDecl()->getName().isSimpleName("self");
1324+
isSelf = DRE->getDecl() == fn->getImplicitSelfDecl();
13241325

13251326
if (!isSelf) {
13261327
ctx.Diags

lib/Sema/TypeCheckType.cpp

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2306,31 +2306,39 @@ bool TypeResolver::diagnoseMoveOnlyMissingOwnership(
23062306
if (options.contains(TypeResolutionFlags::HasOwnership))
23072307
return false;
23082308

2309-
// Do not run this on SIL files since there is currently a bug where we are
2310-
// trying to parse it in SILBoxes.
2311-
//
2312-
// To track what we want to do long term: rdar://105635373.
2309+
// Don't diagnose in SIL; ownership is already required there.
23132310
if (options.contains(TypeResolutionFlags::SILType))
23142311
return false;
23152312

2316-
diagnose(repr->getLoc(),
2317-
diag::moveonly_parameter_missing_ownership);
2313+
//////////////////
2314+
// At this point, we know we have a noncopyable parameter that is missing an
2315+
// ownership specifier, so we need to emit an error
2316+
2317+
// We don't yet support any ownership specifiers for parameters of subscript
2318+
// decls, give a tailored error message saying you simply can't use a
2319+
// noncopyable type here.
2320+
if (options.hasBase(TypeResolverContext::SubscriptDecl)) {
2321+
diagnose(repr->getLoc(), diag::moveonly_parameter_subscript_unsupported);
2322+
} else {
2323+
// general error diagnostic
2324+
diagnose(repr->getLoc(),
2325+
diag::moveonly_parameter_missing_ownership);
23182326

2319-
diagnose(repr->getLoc(), diag::moveonly_parameter_ownership_suggestion,
2320-
"borrowing", "for an immutable reference")
2321-
.fixItInsert(repr->getStartLoc(), "borrowing ");
2327+
diagnose(repr->getLoc(), diag::moveonly_parameter_ownership_suggestion,
2328+
"borrowing", "for an immutable reference")
2329+
.fixItInsert(repr->getStartLoc(), "borrowing ");
23222330

2323-
diagnose(repr->getLoc(), diag::moveonly_parameter_ownership_suggestion,
2324-
"inout", "for a mutable reference")
2325-
.fixItInsert(repr->getStartLoc(), "inout ");
2331+
diagnose(repr->getLoc(), diag::moveonly_parameter_ownership_suggestion,
2332+
"inout", "for a mutable reference")
2333+
.fixItInsert(repr->getStartLoc(), "inout ");
23262334

2327-
diagnose(repr->getLoc(), diag::moveonly_parameter_ownership_suggestion,
2328-
"consuming", "to take the value from the caller")
2329-
.fixItInsert(repr->getStartLoc(), "consuming ");
2335+
diagnose(repr->getLoc(), diag::moveonly_parameter_ownership_suggestion,
2336+
"consuming", "to take the value from the caller")
2337+
.fixItInsert(repr->getStartLoc(), "consuming ");
2338+
}
23302339

23312340
// to avoid duplicate diagnostics
23322341
repr->setInvalid();
2333-
23342342
return true;
23352343
}
23362344

test/Interpreter/moveonly_discard.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ func print_closing_MFD() { print("closing MaybeFileDescriptor") }
99

1010
enum E: Error { case err }
1111

12-
@_moveOnly
13-
struct FileDescriptor {
12+
struct FileDescriptor: ~Copyable {
1413
var fd: Int
1514
static var nextFD: Int = 0
1615

@@ -59,7 +58,7 @@ struct FileDescriptor {
5958
}
6059
}
6160

62-
@_moveOnly enum MaybeFileDescriptor {
61+
enum MaybeFileDescriptor: ~Copyable {
6362
case some(FileDescriptor)
6463
case nothing
6564

@@ -83,6 +82,14 @@ struct FileDescriptor {
8382
}
8483
}
8584

85+
struct SillyEmptyGeneric<T>: ~Copyable {
86+
consuming func identity(_ t: T) -> T {
87+
discard self
88+
return t
89+
}
90+
deinit { fatalError("ran unexpectedly!") }
91+
}
92+
8693
func main() {
8794
let _ = {
8895
let x = FileDescriptor() // 0
@@ -161,6 +168,13 @@ func main() {
161168
// CHECK: closing file descriptor: 13
162169
}()
163170

171+
let _ = {
172+
let x = SillyEmptyGeneric<[Int]>()
173+
let z = [1, 2]
174+
let ans = x.identity(z)
175+
assert(z == ans)
176+
}()
177+
164178
}
165179

166180
main()

test/Sema/discard.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,34 @@ enum NoDeinitEnum: ~Copyable {
161161
discard self // expected-error {{'discard' has no effect for type 'NoDeinitEnum' unless it has a deinitializer}}{{5-18=}}
162162
}
163163
}
164+
165+
struct HasGenericNotStored<T>: ~Copyable { // expected-note 2{{arguments to generic parameter 'T' ('Int' and 'T') are expected to be equal}}
166+
consuming func discard() { discard self }
167+
168+
consuming func bad_discard1() {
169+
discard HasGenericNotStored<Int>()
170+
// expected-error@-1 {{cannot convert value of type 'HasGenericNotStored<Int>' to expected discard type 'HasGenericNotStored<T>'}}
171+
// expected-error@-2 {{you can only discard 'self'}}
172+
}
173+
174+
consuming func bad_discard2() {
175+
let `self` = HasGenericNotStored<Int>()
176+
discard `self`
177+
// expected-error@-1 {{cannot convert value of type 'HasGenericNotStored<Int>' to expected discard type 'HasGenericNotStored<T>'}}
178+
// expected-error@-2 {{you can only discard 'self'}}{{13-19=self}}
179+
}
180+
181+
func identity(_ t: T) -> T { return t }
182+
deinit{}
183+
}
184+
185+
struct Court: ~Copyable {
186+
let x: Int
187+
188+
consuming func discard(_ other: consuming Court) {
189+
let `self` = other
190+
discard `self` // expected-error {{you can only discard 'self'}}{{13-19=self}}
191+
}
192+
193+
deinit { print("deinit of \(self.x)") }
194+
}

test/Sema/discard_trivially_destroyed.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,15 @@ struct AllOK: ~Copyable {
9898
consuming func doDiscard() { discard self }
9999
deinit {}
100100
}
101+
102+
struct HasGenericStored<T>: ~Copyable {
103+
let t: T // expected-note {{type 'T' cannot be trivially destroyed}}
104+
consuming func discard() { discard self } // expected-error {{can only 'discard' type 'HasGenericStored<T>' if it contains trivially-destroyed stored properties at this time}}
105+
deinit{}
106+
}
107+
108+
struct HasAny: ~Copyable {
109+
var t: Any // expected-note {{type 'Any' cannot be trivially destroyed}}
110+
consuming func discard() { discard self } // expected-error {{can only 'discard' type 'HasAny' if it contains trivially-destroyed stored properties at this time}}
111+
deinit{}
112+
}

test/Sema/moveonly_require_ownership_specifier.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,12 @@ func takeInstantiated(_ x: NoncopyableWrapper<Int>) {}
8484
// expected-note@-2 {{add 'borrowing' for an immutable reference}}{{28-28=borrowing }}
8585
// expected-note@-3 {{add 'inout' for a mutable reference}}{{28-28=inout }}
8686
// expected-note@-4 {{add 'consuming' to take the value from the caller}}{{28-28=consuming }}
87+
88+
struct O: ~Copyable {}
89+
90+
public struct M: ~Copyable {
91+
subscript(_ i: O) -> Int { // expected-error {{subscripts cannot have noncopyable parameters}}
92+
get { fatalError() }
93+
set { }
94+
}
95+
}

0 commit comments

Comments
 (0)