Skip to content

Commit f8d688c

Browse files
committed
[Sema] overhaul NoncopyableAnnotationRequest
We need to know whether the noncopyable annotation is inferred from its generic parameters. This allows us to synthesize the conditional conformance.
1 parent a9c64ba commit f8d688c

12 files changed

+461
-211
lines changed

Diff for: include/swift/AST/Decl.h

+3-14
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ namespace swift {
9494
class NamedPattern;
9595
class EnumCaseDecl;
9696
class EnumElementDecl;
97+
struct InverseMarking;
9798
class ParameterList;
9899
class ParameterTypeFlags;
99100
class Pattern;
@@ -3117,16 +3118,6 @@ class TypeDecl : public ValueDecl {
31173118
private:
31183119
ArrayRef<InheritedEntry> Inherited;
31193120

3120-
struct {
3121-
/// Whether the "noncopyableAnnotationKind" field has been computed yet.
3122-
unsigned isNoncopyableAnnotationComputed : 1;
3123-
3124-
unsigned noncopyableAnnotationKind : 2;
3125-
static_assert((unsigned)InverseMarkingKind::LAST < 4);
3126-
3127-
} LazySemanticInfo = { };
3128-
friend class NoncopyableAnnotationRequest;
3129-
31303121
protected:
31313122
TypeDecl(DeclKind K, llvm::PointerUnion<DeclContext *, ASTContext *> context,
31323123
Identifier name, SourceLoc NameLoc,
@@ -3157,12 +3148,10 @@ class TypeDecl : public ValueDecl {
31573148
/// Is it possible for this type to lack a Copyable constraint?
31583149
/// If you need a more precise answer, ask this Decl's corresponding
31593150
/// Type if it `isNoncopyable` instead of using this.
3160-
bool canBeNoncopyable() const {
3161-
return getNoncopyableMarking() != InverseMarkingKind::None;
3162-
}
3151+
bool canBeNoncopyable() const;
31633152

31643153
/// Determine how the ~Copyable was applied to this TypeDecl, if at all.
3165-
InverseMarkingKind getNoncopyableMarking() const;
3154+
InverseMarking getNoncopyableMarking() const;
31663155

31673156
static bool classof(const Decl *D) {
31683157
return D->getKind() >= DeclKind::First_TypeDecl &&

Diff for: include/swift/AST/DiagnosticsSema.def

+13-7
Original file line numberDiff line numberDiff line change
@@ -7533,22 +7533,28 @@ ERROR(accessor_macro_not_single_var, none,
75337533
//------------------------------------------------------------------------------
75347534
// MARK: Noncopyable Types Diagnostics
75357535
//------------------------------------------------------------------------------
7536-
7536+
ERROR(noncopyable_but_copyable, none,
7537+
"%kind0 required to be 'Copyable' but is marked with '~Copyable'",
7538+
(const ValueDecl *))
75377539
ERROR(noncopyable_class, none,
75387540
"classes cannot be noncopyable",
75397541
())
75407542
ERROR(noncopyable_type_member_in_copyable,none,
75417543
"%select{stored property %2|associated value %2}1 of "
75427544
"'Copyable'-conforming %kind3 has noncopyable type %0",
75437545
(Type, bool, DeclName, const ValueDecl *))
7544-
NOTE(add_inverse_for_containment,none,
7545-
"consider removing implicit '%1' conformance from %kind0",
7546+
NOTE(add_inverse,none,
7547+
"consider adding '~%1' to %kind0",
75467548
(const ValueDecl *, StringRef))
7547-
NOTE(remove_inverse_on_generic_parameter_for_conformance,none,
7548-
"consider removing '~%1' from generic parameter %0 so it conforms to the '%1' protocol",
7549+
NOTE(note_inverse_preventing_conformance,none,
7550+
"%0 has '~%1' constraint preventing implicit '%1' conformance",
75497551
(Type, StringRef))
7550-
NOTE(remove_inverse_on_nominal_for_conformance,none,
7551-
"consider removing '~%1' from %kind0 so it conforms to the '%1' protocol",
7552+
NOTE(note_inverse_preventing_conformance_implicit,none,
7553+
"%kind0 has '~%1' constraint on a generic parameter, "
7554+
"making its '%1' conformance conditional",
7555+
(const ValueDecl *, StringRef))
7556+
NOTE(note_inverse_preventing_conformance_explicit,none,
7557+
"%kind0 has '~%1' constraint preventing '%1' conformance",
75527558
(const ValueDecl *, StringRef))
75537559
NOTE(add_explicit_protocol_for_conformance,none,
75547560
"consider making %kind0 explicitly conform to the '%1' protocol",

Diff for: include/swift/AST/InverseMarking.h

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//===- InverseMarking.h - Utilities for tracking inverse types -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_LIB_SEMA_INVERSEMARKING_H
14+
#define SWIFT_LIB_SEMA_INVERSEMARKING_H
15+
16+
#include "swift/AST/KnownProtocols.h"
17+
#include "swift/Basic/SourceLoc.h"
18+
#include "swift/Basic/OptionalEnum.h"
19+
20+
namespace swift {
21+
22+
/// Describes the way an inverse and its corresponding positive contraint
23+
/// appears on a TypeDecl, i.e., the way it was marked.
24+
struct InverseMarking {
25+
enum class Kind : uint8_t {
26+
None, // No inverse marking is present
27+
Inferred, // Inverse is inferred based on generic parameters.
28+
Explicit, // Inverse is explicitly present.
29+
30+
LAST = Explicit
31+
};
32+
33+
// Describes what kind of mark was found, if any.
34+
struct Mark {
35+
private:
36+
OptionalEnum<Kind> kind;
37+
SourceLoc loc;
38+
public:
39+
// Creates an empty mark.
40+
Mark() {};
41+
42+
// Creates a mark.
43+
Mark(Kind k, SourceLoc l = SourceLoc())
44+
: kind(k), loc(l) {};
45+
46+
// Is there an inferred or explicit marking?
47+
bool isPresent() const {
48+
return getKind() != Kind::None;
49+
}
50+
operator bool() { return isPresent(); }
51+
52+
Kind getKind() const {
53+
return kind.getValueOr(Kind::None);
54+
}
55+
56+
SourceLoc getLoc() const { return loc; }
57+
58+
void set(Kind k, SourceLoc l = SourceLoc()) {
59+
assert(!kind.hasValue());
60+
kind = k;
61+
loc = l;
62+
}
63+
64+
void setIfUnset(Kind k, SourceLoc l = SourceLoc()) {
65+
if (kind.hasValue())
66+
return;
67+
set(k, l);
68+
}
69+
70+
void setIfUnset(Mark other) {
71+
if (kind.hasValue())
72+
return;
73+
kind = other.kind;
74+
loc = other.loc;
75+
}
76+
77+
Mark with(Kind k) {
78+
kind = k;
79+
return *this;
80+
}
81+
};
82+
83+
private:
84+
Mark inverse;
85+
Mark positive;
86+
public:
87+
88+
// Creates an empty marking.
89+
InverseMarking() {}
90+
91+
Mark &getInverse() { return inverse; }
92+
Mark &getPositive() { return positive; }
93+
94+
// Merge the results of another marking into this one.
95+
void merge(InverseMarking other) const {
96+
other.inverse.setIfUnset(other.inverse);
97+
other.positive.setIfUnset(other.positive);
98+
}
99+
100+
static InverseMarking forInverse(Kind kind, SourceLoc loc = SourceLoc()) {
101+
InverseMarking marking;
102+
marking.inverse.set(kind, loc);
103+
marking.positive.set(Kind::None);
104+
return marking;
105+
}
106+
};
107+
108+
}
109+
110+
#endif //SWIFT_LIB_SEMA_INVERSEMARKING_H

Diff for: include/swift/AST/KnownProtocols.h

-9
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,6 @@ llvm::Optional<InvertibleProtocolKind>
7373
/// Returns the KnownProtocolKind corresponding to an InvertibleProtocolKind.
7474
KnownProtocolKind getKnownProtocolKind(InvertibleProtocolKind ip);
7575

76-
/// Describes the way an inverse was applied to a TypeDecl.
77-
enum class InverseMarkingKind: uint8_t {
78-
None, // No inverse marking is present
79-
Inferred, // Inverse is inferred based on generic parameters.
80-
Explicit, // Inverse is explicitly present.
81-
82-
LAST = Explicit
83-
};
84-
8576
} // end namespace swift
8677

8778
#endif

Diff for: include/swift/AST/TypeCheckRequests.h

+4-6
Original file line numberDiff line numberDiff line change
@@ -430,22 +430,20 @@ class IsFinalRequest :
430430
/// Determine the kind of noncopyable marking present for this declaration.
431431
class NoncopyableAnnotationRequest
432432
: public SimpleRequest<NoncopyableAnnotationRequest,
433-
InverseMarkingKind(TypeDecl *),
434-
RequestFlags::SeparatelyCached> {
433+
InverseMarking(TypeDecl *),
434+
RequestFlags::Cached> {
435435
public:
436436
using SimpleRequest::SimpleRequest;
437437

438438
private:
439439
friend SimpleRequest;
440440

441441
// Evaluation.
442-
InverseMarkingKind evaluate(Evaluator &evaluator, TypeDecl *decl) const;
442+
InverseMarking evaluate(Evaluator &evaluator, TypeDecl *decl) const;
443443

444444
public:
445-
// Separate caching.
445+
// Caching.
446446
bool isCached() const { return true; }
447-
llvm::Optional<InverseMarkingKind> getCachedResult() const;
448-
void cacheResult(InverseMarkingKind value) const;
449447
};
450448

451449
/// Determine whether the given declaration is escapable.

Diff for: include/swift/AST/TypeCheckerTypeIDZone.def

+2-2
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,8 @@ SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
211211
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,
212212
NoLocationInfo)
213213
SWIFT_REQUEST(TypeChecker, NoncopyableAnnotationRequest,
214-
InverseMarkingKind(TypeDecl *),
215-
SeparatelyCached, NoLocationInfo)
214+
InverseMarking(TypeDecl *),
215+
Cached, NoLocationInfo)
216216
SWIFT_REQUEST(TypeChecker, IsNoncopyableRequest,
217217
bool (CanType),
218218
Cached, NoLocationInfo)

Diff for: lib/AST/Decl.cpp

+11-5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/AST/GenericEnvironment.h"
3232
#include "swift/AST/GenericSignature.h"
3333
#include "swift/AST/Initializer.h"
34+
#include "swift/AST/InverseMarking.h"
3435
#include "swift/AST/LazyResolver.h"
3536
#include "swift/AST/MacroDefinition.h"
3637
#include "swift/AST/MacroDiscriminatorContext.h"
@@ -4876,11 +4877,16 @@ GenericParameterReferenceInfo ValueDecl::findExistentialSelfReferences(
48764877
llvm::None);
48774878
}
48784879

4879-
InverseMarkingKind TypeDecl::getNoncopyableMarking() const {
4880-
return evaluateOrDefault(getASTContext().evaluator,
4881-
NoncopyableAnnotationRequest{
4882-
const_cast<TypeDecl *>(this)},
4883-
InverseMarkingKind::Explicit);
4880+
InverseMarking TypeDecl::getNoncopyableMarking() const {
4881+
return evaluateOrDefault(
4882+
getASTContext().evaluator,
4883+
NoncopyableAnnotationRequest{const_cast<TypeDecl *>(this)},
4884+
InverseMarking::forInverse(InverseMarking::Kind::None)
4885+
);
4886+
}
4887+
4888+
bool TypeDecl::canBeNoncopyable() const {
4889+
return getNoncopyableMarking().getInverse().isPresent();
48844890
}
48854891

48864892
Type TypeDecl::getDeclaredInterfaceType() const {

Diff for: lib/AST/TypeCheckRequests.cpp

-29
Original file line numberDiff line numberDiff line change
@@ -313,35 +313,6 @@ void IsFinalRequest::cacheResult(bool value) const {
313313
decl->getAttrs().add(new (decl->getASTContext()) FinalAttr(/*Implicit=*/true));
314314
}
315315

316-
//----------------------------------------------------------------------------//
317-
// NoncopyableAnnotationRequest computation.
318-
//----------------------------------------------------------------------------//
319-
320-
llvm::Optional<InverseMarkingKind>
321-
NoncopyableAnnotationRequest::getCachedResult() const {
322-
auto decl = std::get<0>(getStorage());
323-
if (decl->LazySemanticInfo.isNoncopyableAnnotationComputed)
324-
return static_cast<InverseMarkingKind>(
325-
decl->LazySemanticInfo.noncopyableAnnotationKind);
326-
327-
return llvm::None;
328-
}
329-
330-
void NoncopyableAnnotationRequest::cacheResult(InverseMarkingKind value) const {
331-
auto decl = std::get<0>(getStorage());
332-
decl->LazySemanticInfo.isNoncopyableAnnotationComputed = true;
333-
decl->LazySemanticInfo.noncopyableAnnotationKind =
334-
static_cast<unsigned>(value);
335-
336-
if (!decl->getASTContext().LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
337-
// Add an attribute for printing
338-
if (value == InverseMarkingKind::Explicit
339-
&& !decl->getAttrs().hasAttribute<MoveOnlyAttr>())
340-
decl->getAttrs().add(new(decl->getASTContext())
341-
MoveOnlyAttr(/*Implicit=*/true));
342-
}
343-
}
344-
345316
//----------------------------------------------------------------------------//
346317
// isEscapable computation.
347318
//----------------------------------------------------------------------------//

0 commit comments

Comments
 (0)