Skip to content

Commit 7816138

Browse files
authored
Merge pull request #65931 from kavon/discard-generics-v2
more `discard` fixes in Sema
2 parents 3f62931 + 1c9ed33 commit 7816138

File tree

3 files changed

+50
-10
lines changed

3 files changed

+50
-10
lines changed

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->getDeclaredTypeInContext();
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

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: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,33 @@ enum NoDeinitEnum: ~Copyable {
162162
}
163163
}
164164

165-
struct HasGenericNotStored<T>: ~Copyable {
165+
struct HasGenericNotStored<T>: ~Copyable { // expected-note 2{{arguments to generic parameter 'T' ('Int' and 'T') are expected to be equal}}
166166
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+
167181
func identity(_ t: T) -> T { return t }
168182
deinit{}
169183
}
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+
}

0 commit comments

Comments
 (0)