Skip to content

Commit 3e03c67

Browse files
committed
[NCGenerics] remove arg from isNoncopyable(DC)
It should be the responsibility of callers to map the type to a contextual type, as needed. When it's not possible or repetitive to do so, there is a special-purpose function `isInterfaceTypeNoncopyable` for Sema.
1 parent 931f47d commit 3e03c67

14 files changed

+80
-57
lines changed

include/swift/AST/Types.h

+5-14
Original file line numberDiff line numberDiff line change
@@ -650,21 +650,12 @@ class alignas(1 << TypeAlignInBits) TypeBase
650650

651651
bool isPlaceholder();
652652

653-
/// Returns true if this type lacks conformance to Copyable in the context,
654-
/// if provided.
655-
bool isNoncopyable(GenericEnvironment *env = nullptr);
656-
bool isNoncopyable(const DeclContext *dc) {
657-
assert(dc);
658-
return isNoncopyable(dc->getGenericEnvironmentOfContext());
659-
};
653+
/// Returns true if this contextual type does not satisfy a conformance to
654+
/// Copyable.
655+
bool isNoncopyable();
660656

661-
/// Returns true if this type conforms to Escapable in the context,
662-
/// if provided.
663-
bool isEscapable(GenericEnvironment *env = nullptr);
664-
bool isEscapable(const DeclContext *dc) {
665-
assert(dc);
666-
return isEscapable(dc->getGenericEnvironmentOfContext());
667-
};
657+
/// Returns true if this contextual type satisfies a conformance to Escapable.
658+
bool isEscapable();
668659

669660
/// Does the type have outer parenthesis?
670661
bool hasParenSugar() const { return getKind() == TypeKind::Paren; }

lib/AST/Type.cpp

+14-10
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,7 @@ static bool alwaysNoncopyable(Type ty) {
178178
}
179179

180180
/// Preprocesses a type before querying whether it conforms to an invertible.
181-
static CanType preprocessTypeForInvertibleQuery(GenericEnvironment *env,
182-
Type orig) {
181+
static CanType preprocessTypeForInvertibleQuery(Type orig) {
183182
Type type = orig;
184183

185184
// Strip off any StorageType wrapper.
@@ -189,31 +188,34 @@ static CanType preprocessTypeForInvertibleQuery(GenericEnvironment *env,
189188
if (auto wrapper = type->getAs<SILMoveOnlyWrappedType>())
190189
type = wrapper->getInnerType();
191190

192-
// Turn any type parameters into archetypes.
193-
if (env)
194-
if (!type->hasArchetype() || type->hasOpenedExistential())
195-
type = GenericEnvironment::mapTypeIntoContext(env, type);
191+
// Pack expansions such as `repeat T` themselves do not have conformances,
192+
// so check its pattern type for conformance.
193+
if (auto *pet = type->getAs<PackExpansionType>()) {
194+
type = pet->getPatternType()->getCanonicalType();
195+
}
196196

197197
// Strip @lvalue and canonicalize.
198198
auto canType = type->getRValueType()->getCanonicalType();
199199
return canType;
200200
}
201201

202202
/// \returns true iff this type lacks conformance to Copyable.
203-
bool TypeBase::isNoncopyable(GenericEnvironment *env) {
204-
auto canType = preprocessTypeForInvertibleQuery(env, this);
203+
bool TypeBase::isNoncopyable() {
204+
auto canType = preprocessTypeForInvertibleQuery(this);
205205
auto &ctx = canType->getASTContext();
206206

207207
// for legacy-mode queries that are not dependent on conformances to Copyable
208208
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics))
209209
return alwaysNoncopyable(canType);
210210

211+
assert(!hasTypeParameter()
212+
&& "requires a contextual type; use mapTypeIntoContext");
211213
IsNoncopyableRequest request{canType};
212214
return evaluateOrDefault(ctx.evaluator, request, /*default=*/true);
213215
}
214216

215-
bool TypeBase::isEscapable(GenericEnvironment *env) {
216-
auto canType = preprocessTypeForInvertibleQuery(env, this);
217+
bool TypeBase::isEscapable() {
218+
auto canType = preprocessTypeForInvertibleQuery(this);
217219
auto &ctx = canType->getASTContext();
218220

219221
// for legacy-mode queries that are not dependent on conformances to Escapable
@@ -224,6 +226,8 @@ bool TypeBase::isEscapable(GenericEnvironment *env) {
224226
return true;
225227
}
226228

229+
assert(!hasTypeParameter()
230+
&& "requires a contextual type; use mapTypeIntoContext");
227231
IsEscapableRequest request{canType};
228232
return evaluateOrDefault(ctx.evaluator, request, /*default=*/false);
229233
}

lib/ClangImporter/ClangImporter.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -5545,10 +5545,11 @@ makeBaseClassMemberAccessors(DeclContext *declContext,
55455545
AbstractStorageDecl *baseClassVar) {
55465546
auto &ctx = declContext->getASTContext();
55475547
auto computedType = computedVar->getInterfaceType();
5548+
auto contextTy = declContext->mapTypeIntoContext(computedType);
55485549

55495550
// Use 'address' or 'mutableAddress' accessors for non-copyable
55505551
// types, unless the base accessor returns it by value.
5551-
bool useAddress = computedType->isNoncopyable(declContext) &&
5552+
bool useAddress = contextTy->isNoncopyable() &&
55525553
(baseClassVar->getReadImpl() == ReadImplKind::Stored ||
55535554
baseClassVar->getAccessor(AccessorKind::Address));
55545555

@@ -5699,9 +5700,11 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
56995700
}
57005701

57015702
if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
5703+
auto contextTy =
5704+
newContext->mapTypeIntoContext(subscript->getElementInterfaceType());
57025705
// Subscripts that return non-copyable types are not yet supported.
57035706
// See: https://github.com/apple/swift/issues/70047.
5704-
if (subscript->getElementInterfaceType()->isNoncopyable(newContext))
5707+
if (contextTy->isNoncopyable())
57055708
return nullptr;
57065709
auto out = SubscriptDecl::create(
57075710
subscript->getASTContext(), subscript->getName(), subscript->getStaticLoc(),

lib/ClangImporter/SwiftDeclSynthesizer.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1756,9 +1756,10 @@ SwiftDeclSynthesizer::makeDereferencedPointeeProperty(FuncDecl *getter,
17561756
: rawElementTy;
17571757
// Use 'address' or 'mutableAddress' accessors for non-copyable
17581758
// types that are returned indirectly.
1759-
bool isImplicit = !elementTy->isNoncopyable(dc);
1759+
bool isNoncopyable = dc->mapTypeIntoContext(elementTy)->isNoncopyable();
1760+
bool isImplicit = !isNoncopyable;
17601761
bool useAddress =
1761-
rawElementTy->getAnyPointerElementType() && elementTy->isNoncopyable(dc);
1762+
rawElementTy->getAnyPointerElementType() && isNoncopyable;
17621763

17631764
auto result = new (ctx)
17641765
VarDecl(/*isStatic*/ false, VarDecl::Introducer::Var,

lib/Sema/AssociatedTypeInference.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ checkTypeWitness(Type type, AssociatedTypeDecl *assocType,
137137
return CheckTypeWitnessResult::forError();
138138

139139
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)
140-
&& type->isNoncopyable(dc)) {
140+
&& type->isNoncopyable()) {
141141
// No move-only type can witness an associatedtype requirement.
142142
// Pretend the failure is a lack of Copyable conformance.
143143
auto *copyable = ctx.getProtocol(KnownProtocolKind::Copyable);

lib/Sema/CSSimplify.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -3889,7 +3889,7 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
38893889
}
38903890

38913891
// move-only types (and their metatypes) cannot match with existential types.
3892-
if (type1->getMetatypeInstanceType()->isNoncopyable(DC)) {
3892+
if (type1->getMetatypeInstanceType()->isNoncopyable()) {
38933893
// tailor error message
38943894
if (shouldAttemptFixes()) {
38953895
auto *fix = MustBeCopyable::create(*this,
@@ -11886,7 +11886,7 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
1188611886

1188711887
// Noncopyable types can't be involved in bridging conversions since a bridged
1188811888
// type assumes the ability to copy.
11889-
if (type1->isNoncopyable(DC)) {
11889+
if (type1->isNoncopyable()) {
1189011890
return SolutionKind::Error;
1189111891
}
1189211892

lib/Sema/MiscDiagnostics.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
325325
tupleExpr->getElementNames());
326326

327327
// Diagnose attempts to form a tuple with any noncopyable elements.
328-
if (E->getType()->isNoncopyable(DC)
328+
if (E->getType()->isNoncopyable()
329329
&& !Ctx.LangOpts.hasFeature(Feature::MoveOnlyTuples)) {
330330
auto noncopyableTy = E->getType();
331331
assert(noncopyableTy->is<TupleType>() && "will use poor wording");
@@ -388,7 +388,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
388388
if (!castType)
389389
return;
390390

391-
if (castType->isNoncopyable(DC)) {
391+
if (castType->isNoncopyable()) {
392392
// can't cast anything to move-only; there should be no valid ones.
393393
Ctx.Diags.diagnose(cast->getLoc(), diag::noncopyable_cast);
394394
return;
@@ -398,7 +398,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
398398
// as of now there is no type it could be cast to except itself, so
399399
// there's no reason for it to happen at runtime.
400400
if (auto fromType = cast->getSubExpr()->getType()) {
401-
if (fromType->isNoncopyable(DC)) {
401+
if (fromType->isNoncopyable()) {
402402
// can't cast move-only to anything.
403403
Ctx.Diags.diagnose(cast->getLoc(), diag::noncopyable_cast);
404404
return;
@@ -4103,7 +4103,7 @@ diagnoseMoveOnlyPatternMatchSubject(ASTContext &C,
41034103
auto subjectType = subjectExpr->getType();
41044104
if (!subjectType
41054105
|| subjectType->hasError()
4106-
|| !subjectType->isNoncopyable(DC)) {
4106+
|| !subjectType->isNoncopyable()) {
41074107
return;
41084108
}
41094109

lib/Sema/TypeCheckAttr.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -7319,8 +7319,7 @@ void AttributeChecker::visitStaticExclusiveOnlyAttr(
73197319
// Can only be applied to structs.
73207320
auto structDecl = cast<StructDecl>(D);
73217321

7322-
if (!structDecl->getDeclaredInterfaceType()
7323-
->isNoncopyable(D->getDeclContext())) {
7322+
if (structDecl->canBeCopyable() != TypeDecl::CBI_Never) {
73247323
diagnoseAndRemoveAttr(attr, diag::attr_static_exclusive_only_noncopyable);
73257324
}
73267325
}

lib/Sema/TypeCheckConstraints.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1726,8 +1726,8 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
17261726
//
17271727
// Thus, right now, a move-only type is only a subtype of itself.
17281728
// We also want to prevent conversions of a move-only type's metatype.
1729-
if (fromType->getMetatypeInstanceType()->isNoncopyable(dc)
1730-
|| toType->getMetatypeInstanceType()->isNoncopyable(dc))
1729+
if (fromType->getMetatypeInstanceType()->isNoncopyable()
1730+
|| toType->getMetatypeInstanceType()->isNoncopyable())
17311731
return CheckedCastKind::Unresolved;
17321732

17331733
// Check for a bridging conversion.

lib/Sema/TypeCheckDeclPrimary.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,10 @@ static Type containsParameterizedProtocolType(Type inheritedTy) {
9090
bool swift::isInterfaceTypeNoncopyable(Type type, GenericEnvironment *env) {
9191
// Turn any type parameters into archetypes.
9292
if (env)
93-
if (!type->hasArchetype() || type->hasOpenedExistential())
94-
type = GenericEnvironment::mapTypeIntoContext(env, type);
93+
type = GenericEnvironment::mapTypeIntoContext(env, type);
94+
95+
if (auto sugar = dyn_cast<SugarType>(type))
96+
type = sugar->getDesugaredType();
9597

9698
if (!type->hasTypeParameter())
9799
return type->isNoncopyable();
@@ -100,8 +102,12 @@ bool swift::isInterfaceTypeNoncopyable(Type type, GenericEnvironment *env) {
100102
if (auto *generic = type->getAnyGeneric())
101103
return generic->canBeCopyable() != swift::TypeDecl::CBI_Always;
102104
else if (auto gtpt = type->getAs<GenericTypeParamType>())
103-
return gtpt->getDecl()->canBeCopyable() != swift::TypeDecl::CBI_Always;
105+
if (auto *gtpd = gtpt->getDecl())
106+
return gtpd->canBeCopyable() != swift::TypeDecl::CBI_Always;
104107

108+
#ifndef NDEBUG
109+
type->dump();
110+
#endif
105111
llvm_unreachable("unhandled type kind");
106112
}
107113

lib/Sema/TypeCheckInvertible.cpp

+5-11
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,10 @@ static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) {
164164
auto *invertible = ctx.getProtocol(getKnownProtocolKind(ip));
165165
assert(invertible);
166166

167-
// Pack expansions such as `repeat T` themselves do not have conformances,
168-
// so check its pattern type for conformance.
169-
if (auto *pet = type->getAs<PackExpansionType>()) {
170-
type = pet->getPatternType()->getCanonicalType();
171-
}
167+
// Must not have a type parameter!
168+
assert(!type->hasTypeParameter() && "caller forgot to mapTypeIntoContext!");
172169

173-
// Must either not have a type parameter, or in the case of a
174-
// BoundGenericXType, have a nominal available.
175-
assert(!type->hasTypeParameter() || type.getAnyNominal()
176-
&& "caller forgot to mapTypeIntoContext!");
170+
assert(!type->is<PackExpansionType>());
177171

178172
// The SIL types in the AST do not have real conformances, and should have
179173
// been handled earlier.
@@ -281,11 +275,11 @@ static bool checkInvertibleConformanceCommon(ProtocolConformance *conformance,
281275
// For a type conforming to IP, ensure that the storage conforms to IP.
282276
switch (IP) {
283277
case InvertibleProtocolKind::Copyable:
284-
if (!type->isNoncopyable(DC))
278+
if (!type->isNoncopyable())
285279
return false;
286280
break;
287281
case InvertibleProtocolKind::Escapable:
288-
if (type->isEscapable(DC))
282+
if (type->isEscapable())
289283
return false;
290284
break;
291285
}

lib/Sema/TypeCheckType.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -2371,7 +2371,7 @@ bool swift::diagnoseMissingOwnership(ASTContext &ctx, DeclContext *dc,
23712371
if (options.hasBase(TypeResolverContext::EnumElementDecl))
23722372
return false; // no need for ownership in enum cases.
23732373

2374-
if (!ty->isNoncopyable(dc))
2374+
if (!isInterfaceTypeNoncopyable(ty, dc->getGenericEnvironmentOfContext()))
23752375
return false; // copyable types do not need ownership
23762376

23772377
if (ownership != ParamSpecifier::Default)
@@ -4776,7 +4776,8 @@ NeverNullType TypeResolver::resolveVarargType(VarargTypeRepr *repr,
47764776
// do not allow move-only types as the element of a vararg
47774777
if (!element->hasError()
47784778
&& inStage(TypeResolutionStage::Interface)
4779-
&& element->isNoncopyable(getDeclContext())) {
4779+
&& isInterfaceTypeNoncopyable(
4780+
element, getDeclContext()->getGenericEnvironmentOfContext())) {
47804781
diagnoseInvalid(repr, repr->getLoc(), diag::noncopyable_generics_variadic,
47814782
element);
47824783
return ErrorType::get(getASTContext());
@@ -4956,7 +4957,8 @@ NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
49564957
// Track the presence of a noncopyable field for diagnostic purposes.
49574958
// We don't need to re-diagnose if a tuple contains another tuple, though,
49584959
// since we should've diagnosed the inner tuple already.
4959-
if (inStage(TypeResolutionStage::Interface) && ty->isNoncopyable(dc)
4960+
if (inStage(TypeResolutionStage::Interface)
4961+
&& isInterfaceTypeNoncopyable(ty, dc->getGenericEnvironmentOfContext())
49604962
&& !moveOnlyElementIndex.has_value() && !isa<TupleTypeRepr>(tyR)) {
49614963
moveOnlyElementIndex = i;
49624964
}

lib/Sema/TypeChecker.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,8 @@ bool isOverrideBasedOnType(const ValueDecl *decl, Type declTy,
14001400
/// could fulfill a protocol requirement for it.
14011401
bool isMemberOperator(FuncDecl *decl, Type type);
14021402

1403-
/// Given an interface type and a decl context, is the type ever noncopyable?
1403+
/// Given an interface type and possibly a generic environment,
1404+
/// is the type ever noncopyable?
14041405
bool isInterfaceTypeNoncopyable(Type interfaceTy, GenericEnvironment *env);
14051406

14061407
/// Returns `true` iff `AdditiveArithmetic` derived conformances are enabled.

test/Generics/inverse_generics.swift

+22
Original file line numberDiff line numberDiff line change
@@ -393,3 +393,25 @@ func checkExistentialAndClasses(
393393
_ b: any Soup & Copyable & ~Escapable & ~Copyable, // expected-error {{composition involving class requirement 'Soup' cannot contain '~Copyable'}}
394394
_ c: some (~Escapable & Removed) & Soup // expected-error {{composition involving class requirement 'Soup' cannot contain '~Escapable'}}
395395
) {}
396+
397+
protocol HasNCBuddy: ~Copyable {
398+
associatedtype NCBuddy: HasNCBuddy, ~Copyable
399+
400+
associatedtype Buddy: HasMember
401+
}
402+
403+
protocol HasMember : HasNCBuddy {
404+
associatedtype Member: HasMember
405+
406+
associatedtype NCMember: ~Copyable
407+
}
408+
409+
func checkOwnership<T: HasMember>(_ t: T,
410+
_ l: T.NCBuddy.Buddy.Member.Buddy,
411+
_ m: T.Member.Member,
412+
_ n: T.Member.NCMember,
413+
// expected-error@-1 {{parameter of noncopyable type 'T.Member.NCMember' must specify ownership}} // expected-note@-1 3{{add}}
414+
415+
_ o: T.Member.NCBuddy.NCBuddy
416+
// expected-error@-1 {{parameter of noncopyable type 'T.Member.NCBuddy.NCBuddy' must specify ownership}} // expected-note@-1 3{{add}}
417+
) {}

0 commit comments

Comments
 (0)