Skip to content

Commit e75c451

Browse files
committed
[Sema] redo parameter ownership checking
We really should be checking for the presence of the ownership annotation from the top of the parameter's TypeRepr hierarchy, instead of the bottom. This fixes some missed edge cases that are now relevant, like `some ~Copyable`. parameters
1 parent bfb36e4 commit e75c451

File tree

7 files changed

+65
-64
lines changed

7 files changed

+65
-64
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7509,7 +7509,7 @@ ERROR(noncopyable_cannot_conform_to_type, none,
75097509
"noncopyable %kind0 cannot conform to %1",
75107510
(const ValueDecl *, Type))
75117511
ERROR(noncopyable_parameter_requires_ownership, none,
7512-
"noncopyable parameter must specify its ownership", ())
7512+
"parameter of noncopyable type %0 must specify ownership", (Type))
75137513
ERROR(noncopyable_parameter_subscript_unsupported, none,
75147514
"subscripts cannot have noncopyable parameters yet", ())
75157515
NOTE(noncopyable_parameter_ownership_suggestion, none,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2443,12 +2443,16 @@ static Type validateParameterType(ParamDecl *decl) {
24432443
Type Ty;
24442444

24452445
auto *nestedRepr = decl->getTypeRepr();
2446+
ParamSpecifier ownership = ParamSpecifier::Default;
24462447
while (true) {
24472448
if (auto *attrTypeRepr = dyn_cast<AttributedTypeRepr>(nestedRepr)) {
24482449
nestedRepr = attrTypeRepr->getTypeRepr();
24492450
continue;
24502451
}
24512452
if (auto *specifierTypeRepr = dyn_cast<SpecifierTypeRepr>(nestedRepr)) {
2453+
if (specifierTypeRepr->getKind() == TypeReprKind::Ownership)
2454+
ownership = cast<OwnershipTypeRepr>(specifierTypeRepr)->getSpecifier();
2455+
24522456
nestedRepr = specifierTypeRepr->getBase();
24532457
continue;
24542458
}
@@ -2494,6 +2498,13 @@ static Type validateParameterType(ParamDecl *decl) {
24942498
return ErrorType::get(ctx);
24952499
}
24962500

2501+
// Validate the presence of ownership for a noncopyable parameter.
2502+
if (diagnoseMissingOwnership(ctx, dc, ownership,
2503+
decl->getTypeRepr(), Ty, options)) {
2504+
decl->setInvalid();
2505+
return ErrorType::get(ctx);
2506+
}
2507+
24972508
return Ty;
24982509
}
24992510

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -732,12 +732,8 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
732732

733733
auto paramOptions = baseOptions;
734734

735-
if (auto *specifier = dyn_cast<SpecifierTypeRepr>(typeRepr)) {
736-
if (isa<OwnershipTypeRepr>(specifier))
737-
paramOptions |= TypeResolutionFlags::HasOwnership;
738-
735+
if (auto *specifier = dyn_cast<SpecifierTypeRepr>(typeRepr))
739736
typeRepr = specifier->getBase();
740-
}
741737

742738
if (auto *packExpansion = dyn_cast<VarargTypeRepr>(typeRepr)) {
743739
paramOptions.setContext(TypeResolverContext::VariadicFunctionInput);

lib/Sema/TypeCheckType.cpp

Lines changed: 31 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,8 +2086,6 @@ namespace {
20862086

20872087
bool diagnoseMoveOnlyGeneric(TypeRepr *repr,
20882088
Type unboundTy, Type genericArgTy);
2089-
bool diagnoseMissingOwnership(TypeRepr *repr,
2090-
TypeResolutionOptions options);
20912089

20922090
bool diagnoseDisallowedExistential(TypeRepr *repr);
20932091

@@ -2360,60 +2358,49 @@ bool TypeResolver::diagnoseMoveOnlyGeneric(TypeRepr *repr,
23602358
return false;
23612359
}
23622360

2363-
/// Assuming this repr has resolved to a noncopyable type, checks
2364-
/// to see if that resolution happened in a context requiring an ownership
2365-
/// annotation. If it did and there was no ownership specified, emits a
2366-
/// diagnostic.
2367-
///
2368-
/// \returns true if an error diagnostic was emitted
2369-
bool TypeResolver::diagnoseMissingOwnership(TypeRepr *repr,
2370-
TypeResolutionOptions options) {
2371-
// Though this is only required on function inputs... we can ignore
2372-
// InoutFunctionInput since it's already got ownership.
2373-
if (!options.is(TypeResolverContext::FunctionInput))
2374-
return false;
23752361

2376-
// Enum cases don't need to specify ownership for associated values
2362+
bool swift::diagnoseMissingOwnership(ASTContext &ctx, DeclContext *dc,
2363+
ParamSpecifier ownership,
2364+
TypeRepr *repr, Type ty,
2365+
TypeResolutionOptions options) {
2366+
assert(!ty->hasError());
2367+
assert(!options.contains(TypeResolutionFlags::SILType));
2368+
23772369
if (options.hasBase(TypeResolverContext::EnumElementDecl))
2378-
return false;
2370+
return false; // no need for ownership in enum cases.
23792371

2380-
// Otherwise, we require ownership.
2381-
if (options.contains(TypeResolutionFlags::HasOwnership))
2382-
return false;
2372+
if (!ty->isNoncopyable(dc))
2373+
return false; // copyable types do not need ownership
23832374

2384-
// Don't diagnose in SIL; ownership is already required there.
2385-
if (options.contains(TypeResolutionFlags::SILType))
2386-
return false;
2375+
if (ownership != ParamSpecifier::Default)
2376+
return false; // it has ownership
23872377

2388-
//////////////////
2389-
// At this point, we know we have a noncopyable parameter that is missing an
2390-
// ownership specifier, so we need to emit an error
2378+
auto &diags = ctx.Diags;
2379+
auto loc = repr->getLoc();
2380+
repr->setInvalid();
23912381

23922382
// We don't yet support any ownership specifiers for parameters of subscript
23932383
// decls, give a tailored error message saying you simply can't use a
23942384
// noncopyable type here.
23952385
if (options.hasBase(TypeResolverContext::SubscriptDecl)) {
2396-
diagnose(repr->getLoc(), diag::noncopyable_parameter_subscript_unsupported);
2386+
diags.diagnose(loc, diag::noncopyable_parameter_subscript_unsupported);
23972387
} else {
23982388
// general error diagnostic
2399-
diagnose(repr->getLoc(),
2400-
diag::noncopyable_parameter_requires_ownership);
2389+
diags.diagnose(loc, diag::noncopyable_parameter_requires_ownership, ty);
24012390

2402-
diagnose(repr->getLoc(), diag::noncopyable_parameter_ownership_suggestion,
2403-
"borrowing", "for an immutable reference")
2391+
diags.diagnose(loc, diag::noncopyable_parameter_ownership_suggestion,
2392+
"borrowing", "for an immutable reference")
24042393
.fixItInsert(repr->getStartLoc(), "borrowing ");
24052394

2406-
diagnose(repr->getLoc(), diag::noncopyable_parameter_ownership_suggestion,
2407-
"inout", "for a mutable reference")
2395+
diags.diagnose(loc, diag::noncopyable_parameter_ownership_suggestion,
2396+
"inout", "for a mutable reference")
24082397
.fixItInsert(repr->getStartLoc(), "inout ");
24092398

2410-
diagnose(repr->getLoc(), diag::noncopyable_parameter_ownership_suggestion,
2411-
"consuming", "to take the value from the caller")
2399+
diags.diagnose(loc, diag::noncopyable_parameter_ownership_suggestion,
2400+
"consuming", "to take the value from the caller")
24122401
.fixItInsert(repr->getStartLoc(), "consuming ");
24132402
}
24142403

2415-
// to avoid duplicate diagnostics
2416-
repr->setInvalid();
24172404
return true;
24182405
}
24192406

@@ -3473,6 +3460,8 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr,
34733460
SmallVector<AnyFunctionType::Param, 8> elements;
34743461
elements.reserve(inputRepr->getNumElements());
34753462

3463+
auto *dc = getDeclContext();
3464+
34763465
auto elementOptions = options.withoutContext(true);
34773466
elementOptions.setContext(TypeResolverContext::FunctionInput);
34783467
for (unsigned i = 0, end = inputRepr->getNumElements(); i != end; ++i) {
@@ -3517,7 +3506,7 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr,
35173506
if (ATR->getAttrs().has(TAK_noDerivative)) {
35183507
if (diffKind == DifferentiabilityKind::NonDifferentiable &&
35193508
isDifferentiableProgrammingEnabled(
3520-
*getDeclContext()->getParentSourceFile()))
3509+
*dc->getParentSourceFile()))
35213510
diagnose(nestedRepr->getLoc(),
35223511
diag::attr_only_on_parameters_of_differentiable,
35233512
"@noDerivative")
@@ -3565,6 +3554,11 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr,
35653554
}
35663555
}
35673556

3557+
// Validate the presence of ownership for a noncopyable parameter.
3558+
if (inStage(TypeResolutionStage::Interface))
3559+
diagnoseMissingOwnership(getASTContext(), dc, ownership,
3560+
eltTypeRepr, ty, options);
3561+
35683562
Identifier argumentLabel;
35693563
Identifier parameterName;
35703564
if (inputRepr->getElement(i).NameLoc.isValid() &&
@@ -4389,10 +4383,6 @@ TypeResolver::resolveDeclRefTypeRepr(DeclRefTypeRepr *repr,
43894383
}
43904384
}
43914385

4392-
// Noncopyable types must have an ownership specifier when used as a parameter
4393-
if (inStage(TypeResolutionStage::Interface) && result->isNoncopyable(dc))
4394-
diagnoseMissingOwnership(repr, options);
4395-
43964386
// Hack to apply context-specific @escaping to a typealias with an underlying
43974387
// function type.
43984388
if (result->is<FunctionType>())
@@ -4435,9 +4425,6 @@ TypeResolver::resolveOwnershipTypeRepr(OwnershipTypeRepr *repr,
44354425
options.setContext(TypeResolverContext::InoutFunctionInput);
44364426
}
44374427

4438-
// Remember that we've seen an ownership specifier for this base type.
4439-
options |= TypeResolutionFlags::HasOwnership;
4440-
44414428
auto result = resolveType(repr->getBase(), options);
44424429
if (result->hasError())
44434430
return result;

lib/Sema/TypeCheckType.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,6 @@ enum class TypeResolutionFlags : uint16_t {
8282

8383
/// Whether this is a resolution based on a pack reference.
8484
FromPackReference = 1 << 12,
85-
86-
/// Whether this resolution happens under an explicit ownership specifier.
87-
HasOwnership = 1 << 13,
8885
};
8986

9087
/// Type resolution contexts that require special handling.
@@ -669,6 +666,16 @@ void diagnoseInvalidGenericArguments(SourceLoc loc,
669666
bool hasParameterPack,
670667
GenericIdentTypeRepr *generic);
671668

669+
/// \param repr the repr for the type of the parameter.
670+
/// \param ty the non-error resolved type of the repr.
671+
/// \param ownership the ownership kind of the parameter
672+
/// \param dc the decl context used for resolving the type
673+
/// \returns true iff a diagnostic was emitted and the \c repr was invalidated.
674+
bool diagnoseMissingOwnership(ASTContext &ctx, DeclContext *dc,
675+
ParamSpecifier ownership,
676+
TypeRepr *repr, Type ty,
677+
TypeResolutionOptions options);
678+
672679
} // end namespace swift
673680

674681
#endif /* SWIFT_SEMA_TYPE_CHECK_TYPE_H */

test/Concurrency/custom_executor_enqueue_impls.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ final class NewExecutor: SerialExecutor {
8282
}
8383

8484
// Good impl, but missing the ownership keyword
85-
final class MissingOwnership: SerialExecutor {
86-
func enqueue(_ job: ExecutorJob) {} // expected-error{{noncopyable parameter must specify its ownership}}
85+
final class MissingOwnership: SerialExecutor { // expected-error {{type 'MissingOwnership' does not conform to protocol 'Executor'}}
86+
func enqueue(_ job: ExecutorJob) {} // expected-error{{parameter of noncopyable type 'ExecutorJob' must specify ownership}}
8787
// expected-note@-1{{add 'borrowing' for an immutable reference}}
8888
// expected-note@-2{{add 'inout' for a mutable reference}}
8989
// expected-note@-3{{add 'consuming' to take the value from the caller}}

test/Sema/moveonly_require_ownership_specifier.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,26 @@ public struct NoncopyableWrapper<T> {
1717

1818
class Inspector {
1919
func inspect(_ hasIt: inout MO, _ mo: MO, _ hasItAgain: __owned MO) {}
20-
// expected-error@-1 {{noncopyable parameter must specify its ownership}}
20+
// expected-error@-1 {{parameter of noncopyable type 'MO' must specify ownership}}
2121
// expected-note@-2 {{add 'borrowing' for an immutable reference}}{{41-41=borrowing }}
2222
// expected-note@-3 {{add 'inout' for a mutable reference}}{{41-41=inout }}
2323
// expected-note@-4 {{add 'consuming' to take the value from the caller}}{{41-41=consuming }}
2424
}
2525

26-
// expected-error@+4 {{noncopyable parameter must specify its ownership}}
26+
// expected-error@+4 {{parameter of noncopyable type 'MO' must specify ownership}}
2727
// expected-note@+3 {{add 'borrowing' for an immutable reference}}{{20-20=borrowing }}
2828
// expected-note@+2 {{add 'inout' for a mutable reference}}{{20-20=inout }}
2929
// expected-note@+1 {{add 'consuming' to take the value from the caller}}{{20-20=consuming }}
3030
func applier(_ f: (MO) -> (),
3131
_ v: MO) {}
32-
// expected-error@-1 {{noncopyable parameter must specify its ownership}}
32+
// expected-error@-1 {{parameter of noncopyable type 'MO' must specify ownership}}
3333
// expected-note@-2 {{add 'borrowing' for an immutable reference}}{{19-19=borrowing }}
3434
// expected-note@-3 {{add 'inout' for a mutable reference}}{{19-19=inout }}
3535
// expected-note@-4 {{add 'consuming' to take the value from the caller}}{{19-19=consuming }}
3636

3737
func caller() {
3838
let f = { (_ mo1: MO, _ mo2: MO) in () }
39-
// expected-error@-1 2{{noncopyable parameter must specify its ownership}}
39+
// expected-error@-1 2{{parameter of noncopyable type 'MO' must specify ownership}}
4040
// expected-note@-2 {{add 'borrowing' for an immutable reference}}{{21-21=borrowing }}
4141
// expected-note@-3 {{add 'borrowing' for an immutable reference}}{{32-32=borrowing }}
4242
// expected-note@-4 {{add 'inout' for a mutable reference}}{{21-21=inout }}
@@ -45,7 +45,7 @@ func caller() {
4545
// expected-note@-7 {{add 'consuming' to take the value from the caller}}{{32-32=consuming }}
4646

4747
let g: (MO, MO) -> () = f
48-
// expected-error@-1 2{{noncopyable parameter must specify its ownership}}
48+
// expected-error@-1 2{{parameter of noncopyable type 'MO' must specify ownership}}
4949
// expected-note@-2 {{add 'borrowing' for an immutable reference}}{{11-11=borrowing }}
5050
// expected-note@-3 {{add 'borrowing' for an immutable reference}}{{15-15=borrowing }}
5151
// expected-note@-4 {{add 'inout' for a mutable reference}}{{11-11=inout }}
@@ -56,7 +56,7 @@ func caller() {
5656
let partialG = { g($0, MO()) }
5757

5858
let _: Box<(MO) -> ()> = Box(val: partialG)
59-
// expected-error@-1 {{noncopyable parameter must specify its ownership}}
59+
// expected-error@-1 {{parameter of noncopyable type 'MO' must specify ownership}}
6060
// expected-note@-2 {{add 'borrowing' for an immutable reference}}{{15-15=borrowing }}
6161
// expected-note@-3 {{add 'inout' for a mutable reference}}{{15-15=inout }}
6262
// expected-note@-4 {{add 'consuming' to take the value from the caller}}{{15-15=consuming }}
@@ -65,7 +65,7 @@ func caller() {
6565
let _: Box<(borrowing MO) -> ()>? = nil
6666

6767
let _: Box<(MO) -> ()>? = nil
68-
// expected-error@-1 {{noncopyable parameter must specify its ownership}}
68+
// expected-error@-1 {{parameter of noncopyable type 'MO' must specify ownership}}
6969
// expected-note@-2 {{add 'borrowing' for an immutable reference}}{{15-15=borrowing }}
7070
// expected-note@-3 {{add 'inout' for a mutable reference}}{{15-15=inout }}
7171
// expected-note@-4 {{add 'consuming' to take the value from the caller}}{{15-15=consuming }}
@@ -74,13 +74,13 @@ func caller() {
7474
}
7575

7676
func takeGeneric<T>(_ x: NoncopyableWrapper<T>) {}
77-
// expected-error@-1 {{noncopyable parameter must specify its ownership}}
77+
// expected-error@-1 {{parameter of noncopyable type 'NoncopyableWrapper<T>' must specify ownership}}
7878
// expected-note@-2 {{add 'borrowing' for an immutable reference}}{{26-26=borrowing }}
7979
// expected-note@-3 {{add 'inout' for a mutable reference}}{{26-26=inout }}
8080
// expected-note@-4 {{add 'consuming' to take the value from the caller}}{{26-26=consuming }}
8181

8282
func takeInstantiated(_ x: NoncopyableWrapper<Int>) {}
83-
// expected-error@-1 {{noncopyable parameter must specify its ownership}}
83+
// expected-error@-1 {{parameter of noncopyable type 'NoncopyableWrapper<Int>' must specify ownership}}
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 }}

0 commit comments

Comments
 (0)