[Sema] Insert ErrorType same-type constraints for placeholder signatures

This helps avoid producing more downstream errors. This changes
`GenericSignature::forInvalid` to produce the same signature as e.g
`<T where T == Undefined>`. This subsumes the need to introduce
conformance requirements for invertible protocols.
This commit is contained in:
Hamish Knight
2025-10-08 21:16:02 +01:00
parent 71841bdbd5
commit e7c7239587
7 changed files with 10 additions and 23 deletions

View File

@@ -6012,16 +6012,16 @@ GenericSignature::forInvalid(ArrayRef<GenericTypeParamType *> params) {
ASSERT(!params.empty());
auto &ctx = params.front()->getASTContext();
// Add same type requirements that make each of the generic parameters
// concrete error types. This helps avoid downstream diagnostics and is
// handled the same as if the user wrote e.g `<T where T == Undefined>`.
SmallVector<Requirement, 2> requirements;
for (auto *param : params) {
if (param->isValue())
continue;
for (auto ip : InvertibleProtocolSet::allKnown()) {
auto *proto = ctx.getProtocol(getKnownProtocolKind(ip));
requirements.emplace_back(RequirementKind::Conformance, param,
proto->getDeclaredInterfaceType());
}
requirements.emplace_back(RequirementKind::SameType, param,
ErrorType::get(ctx));
}
return GenericSignature::get(params, requirements);
}

View File

@@ -1643,8 +1643,7 @@ bool GenericContext::isComputingGenericSignature() const {
/// If we hit a cycle while building the generic signature, we can't return
/// nullptr, since this breaks invariants elsewhere. Instead, build a dummy
/// signature where everything is Copyable and Escapable, to avoid spurious
/// downstream diagnostics concerning move-only types.
/// invalid signature to avoid spurious downstream diagnostics.
static GenericSignature getPlaceholderGenericSignature(
ASTContext &ctx, const DeclContext *DC) {
SmallVector<GenericParamList *, 2> gpLists;

View File

@@ -282,15 +282,11 @@ protocol P2 {
}
// CHECK-LABEL: same_types.(file).structuralSameTypeRecursive1@
// CHECK-NEXT: Generic signature: <T, U>
// CHECK-NEXT: Generic signature: <T, U where T == <<error type>>, U == <<error type>>>
// expected-error@+2 {{cannot build rewrite system for generic signature; concrete type nesting limit exceeded}}
// expected-note@+1 {{τ_0_0.[P2:Assoc1].[concrete: ((((((((((((((((((((((((((((((((τ_0_0.[P2:Assoc1], τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1)] => τ_0_0.[P2:Assoc1]}}
func structuralSameTypeRecursive1<T: P2, U>(_: T, _: U)
where T.Assoc1 == Tuple2<T.Assoc1, U>
// expected-error@-1 {{'Assoc1' is not a member type of type 'T'}}
// expected-error@-2 {{'Assoc1' is not a member type of type 'T'}}
{ }
func structuralSameTypeRecursive1<T: P2, U>(_: T, _: U) where T.Assoc1 == Tuple2<T.Assoc1, U> {}
protocol P3 {
}

View File

@@ -55,8 +55,6 @@ class G<T> {
@_specialize(where T == S<T>)
// expected-error@-1 {{cannot build rewrite system for generic signature; concrete type nesting limit exceeded}}
// expected-note@-2 {{failed rewrite rule is τ_0_0.[concrete: S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<τ_0_0>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => τ_0_0}}
// expected-error@-3 {{too few generic parameters are specified in '_specialize' attribute (got 0, but expected 1)}}
// expected-note@-4 {{missing constraint for 'T' in '_specialize' attribute}}
@_specialize(where T == Int, U == Int) // expected-error{{cannot find type 'U' in scope}}
func noGenericParams() {}

View File

@@ -11,10 +11,8 @@ extension SomeProtocol where T == Optional<T> { }
// rdar://problem/19840527
class X<T> where T == X {
// expected-error@-1 {{cannot build rewrite system for generic signature; concrete type nesting limit exceeded}}
// expected-note@-2 {{failed rewrite rule is τ_0_0.[concrete: X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<τ_0_0>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => τ_0_0}}
// expected-error@-3 {{generic class 'X' has self-referential generic requirements}}
var type: T { return Swift.type(of: self) } // expected-error{{cannot convert return expression of type 'X<T>.Type' to return type 'T'}}
// expected-error@-1 {{generic class 'X' has self-referential generic requirements}}
var type: T { return Swift.type(of: self) }
}
// FIXME: The "associated type 'Foo' is not a member type of 'Self'" diagnostic

View File

@@ -13,5 +13,4 @@ extension Type: P where Param: P, Param.A == Type<Param> {
// expected-error@-3 {{type 'Type<Param>' does not conform to protocol 'P'}}
// expected-note@-4 {{add stubs for conformance}}
typealias A = Param
// expected-note@-1 {{possibly intended match 'Type<Param>.A' (aka 'Param') does not conform to 'P'}}
}

View File

@@ -13,9 +13,6 @@ extension S: P where N: P {
static func f<X: P>(_ x: X) -> S<X.A> where A == X, X.A == N {
// expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}}
// expected-note@-2 {{τ_0_0.[P:A].[P:A].[P:A].[P:A].[P:A].[concrete: S<S<S<S<S<S<τ_0_0>>>>>>] => τ_0_0.[P:A].[P:A].[P:A].[P:A].[P:A] [subst]}}
// expected-error@-3 {{'A' is not a member type of type 'X'}}
// expected-error@-4 {{'A' is not a member type of type 'X'}}
return S<X.A>()
// expected-error@-1 {{'A' is not a member type of type 'X'}}
}
}