[Sema] Quick fix for non-copyable type resolution crash

Add a guard to make sure we don't attempt to check for Copyable
conformance if the type contains type variables. This matches the
existing behavior where we won't check for unbound generic types.
Neither behavior is correct since we won't do the proper check once
the generic type is opened, but this at least makes the behavior
consistent and fixes the crash. It's also a very low risk fix that
can be cherry-picked.

rdar://152287178
This commit is contained in:
Hamish Knight
2025-10-15 13:03:13 +01:00
parent f449b7bcc1
commit 7629fbd0e0
4 changed files with 19 additions and 1 deletions

View File

@@ -3958,8 +3958,9 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr,
} }
// Validate the presence of ownership for a noncopyable parameter. // Validate the presence of ownership for a noncopyable parameter.
// FIXME: This won't diagnose if the type contains unbound generics.
if (inStage(TypeResolutionStage::Interface) if (inStage(TypeResolutionStage::Interface)
&& !ty->hasUnboundGenericType()) { && !ty->hasUnboundGenericType() && !ty->hasTypeVariable()) {
diagnoseMissingOwnership(ownership, eltTypeRepr, ty, resolution); diagnoseMissingOwnership(ownership, eltTypeRepr, ty, resolution);
// @_staticExclusiveOnly types cannot be passed as 'inout' in function // @_staticExclusiveOnly types cannot be passed as 'inout' in function
@@ -5709,6 +5710,7 @@ NeverNullType TypeResolver::resolveVarargType(VarargTypeRepr *repr,
} }
// do not allow move-only types as the element of a vararg // do not allow move-only types as the element of a vararg
// FIXME: This does not correctly handle type variables and unbound generics.
if (inStage(TypeResolutionStage::Interface)) { if (inStage(TypeResolutionStage::Interface)) {
auto contextTy = GenericEnvironment::mapTypeIntoContext( auto contextTy = GenericEnvironment::mapTypeIntoContext(
resolution.getGenericSignature().getGenericEnvironment(), element); resolution.getGenericSignature().getGenericEnvironment(), element);
@@ -5895,6 +5897,7 @@ NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
// Track the presence of a noncopyable field for diagnostic purposes only. // Track the presence of a noncopyable field for diagnostic purposes only.
// We don't need to re-diagnose if a tuple contains another tuple, though, // We don't need to re-diagnose if a tuple contains another tuple, though,
// since we should've diagnosed the inner tuple already. // since we should've diagnosed the inner tuple already.
// FIXME: This won't diagnose if the type contains unbound generics
if (!ctx.LangOpts.hasFeature(Feature::MoveOnlyTuples) && if (!ctx.LangOpts.hasFeature(Feature::MoveOnlyTuples) &&
!options.contains(TypeResolutionFlags::SILMode) && !options.contains(TypeResolutionFlags::SILMode) &&
inStage(TypeResolutionStage::Interface) && inStage(TypeResolutionStage::Interface) &&

View File

@@ -40,3 +40,8 @@ func test_ambiguity_with_placeholders(pairs: [(rank: Int, count: Int)]) -> Bool
let unboundInPlaceholder1: Array<Never> = <#T##Array#> // expected-error{{editor placeholder in source file}} let unboundInPlaceholder1: Array<Never> = <#T##Array#> // expected-error{{editor placeholder in source file}}
let unboundInPlaceholder2: Array<Never> = foo(<#T##t: Array##Array<Never>#>) // expected-error{{editor placeholder in source file}} let unboundInPlaceholder2: Array<Never> = foo(<#T##t: Array##Array<Never>#>) // expected-error{{editor placeholder in source file}}
// Make sure this doesn't crash:
<#T##(Result) -> Void#> // expected-error {{editor placeholder in source file}}
// expected-error@-1 {{generic parameter 'Success' could not be inferred}}
// expected-error@-2 {{generic parameter 'Failure' could not be inferred}}

View File

@@ -0,0 +1,5 @@
// {"kind":"typecheck","signature":"checkRequirementsImpl(llvm::ArrayRef<swift::Requirement>, bool)","signatureAssert":"Assertion failed: (!firstType->hasTypeVariable()), function checkRequirementsImpl"}
// RUN: not %target-swift-frontend -typecheck %s
struct a<b: ~Copyable
extension a: Copyable where b: Copyable
let c (a -> d

View File

@@ -0,0 +1,5 @@
// {"kind":"typecheck","signature":"checkRequirementsImpl(llvm::ArrayRef<swift::Requirement>, bool)","signatureAssert":"Assertion failed: (!firstType->hasTypeVariable()), function checkRequirementsImpl"}
// RUN: not %target-swift-frontend -typecheck %s
struct a<b: ~Copyable
extension a: Copyable where b: Copyable
let c = <#T##(a -> d)#>