Merge pull request #84730 from swiftlang/jepa-main2

RequirementMachine: Diagnose unsupported value generic parameter definitions properly
This commit is contained in:
Anthony Latsis
2025-10-08 21:12:00 +01:00
committed by GitHub
7 changed files with 77 additions and 45 deletions

View File

@@ -8597,8 +8597,8 @@ ERROR(value_type_used_in_type_parameter,none,
"cannot use value type %0 for generic argument %1", (Type, Type))
ERROR(invalid_value_type_value_generic,none,
"%0 is not a supported value type for %1", (Type, Type))
ERROR(invalid_value_generic_conformance,none,
"value generic type %0 cannot conform to protocol %1", (Type, Type))
ERROR(invalid_value_generic_constraint,none,
"cannot use type constraint with generic value parameter %0", (Type))
ERROR(invalid_value_generic_same_type,none,
"cannot constrain value parameter %0 to be type %1", (Type, Type))
ERROR(integer_type_not_accepted,none,

View File

@@ -247,14 +247,14 @@ bool swift::rewriting::diagnoseRequirementErrors(
break;
}
case RequirementError::Kind::InvalidValueGenericConformance: {
case RequirementError::Kind::InvalidValueGenericConstraint: {
auto req = error.getRequirement();
if (req.hasError())
break;
ctx.Diags.diagnose(loc, diag::invalid_value_generic_conformance,
req.getFirstType(), req.getSecondType());
ctx.Diags.diagnose(loc, diag::invalid_value_generic_constraint,
req.getFirstType());
diagnosedError = true;
break;
}

View File

@@ -59,9 +59,9 @@ struct RequirementError {
/// An unexpected value type used in a value generic,
/// e.g. 'let N: String'.
InvalidValueGenericType,
/// A value generic type was used to conform to a protocol,
/// e.g. 'where N: P' where N == 'let N: Int' and P is some protocol.
InvalidValueGenericConformance,
/// A generic value parameter was used as the subject of a subtype
/// constraint, e.g. `N: X` in `struct S<let N: Int> where N: X`.
InvalidValueGenericConstraint,
/// A value generic type was used to same-type to an unrelated type,
/// e.g. 'where N == Int' where N == 'let N: Int'.
InvalidValueGenericSameType,
@@ -176,9 +176,12 @@ public:
return {Kind::InvalidValueGenericType, requirement, loc};
}
static RequirementError forInvalidValueGenericConformance(Requirement req,
SourceLoc loc) {
return {Kind::InvalidValueGenericConformance, req, loc};
static RequirementError forInvalidValueGenericConstraint(Type subjectType,
Type constraint,
SourceLoc loc) {
Requirement requirement(RequirementKind::Conformance, subjectType,
constraint);
return {Kind::InvalidValueGenericConstraint, requirement, loc};
}
static RequirementError forInvalidValueGenericSameType(Type subjectType,

View File

@@ -389,15 +389,6 @@ static void desugarConformanceRequirement(
// Fast path.
if (constraintType->is<ProtocolType>()) {
// Diagnose attempts to introduce a value generic like 'let N: P' where 'P'
// is some protocol in either the defining context or in an extension where
// clause.
if (req.getFirstType()->isValueParameter()) {
errors.push_back(
RequirementError::forInvalidValueGenericConformance(req, loc));
return;
}
if (req.getFirstType()->isTypeParameter()) {
result.push_back(req);
return;
@@ -538,7 +529,26 @@ void swift::rewriting::realizeTypeRequirement(DeclContext *dc,
Type constraintType,
SourceLoc loc,
SmallVectorImpl<StructuralRequirement> &result,
SmallVectorImpl<RequirementError> &errors) {
SmallVectorImpl<RequirementError> &errors,
bool isFromInheritanceClause) {
// Handle value generics first.
if (subjectType->isValueParameter()) {
if (isFromInheritanceClause) {
if (!constraintType->isLegalValueGenericType()) {
// The definition of a generic value parameter has an unsupported type,
// e.g. `<let N: UInt8>`.
errors.push_back(RequirementError::forInvalidValueGenericType(
subjectType, constraintType, loc));
}
} else {
// A generic value parameter was used as the subject of a subtype
// constraint, e.g. `N: X` in `struct S<let N: Int> where N: X`.
errors.push_back(RequirementError::forInvalidValueGenericConstraint(
subjectType, constraintType, loc));
}
return;
}
// The GenericSignatureBuilder allowed the right hand side of a
// conformance or superclass requirement to reference a protocol
// typealias whose underlying type was a protocol or class.
@@ -574,22 +584,6 @@ void swift::rewriting::realizeTypeRequirement(DeclContext *dc,
result.push_back({Requirement(RequirementKind::Superclass,
subjectType, constraintType),
loc});
} else if (subjectType->isValueParameter() && !isa<ExtensionDecl>(dc)) {
// This is a correct value generic definition where 'let N: Int'.
//
// Note: This definition is only valid in non-extension contexts. If we are
// in an extension context then the user has written something like:
// 'extension T where N: Int' which is weird and not supported.
if (constraintType->isLegalValueGenericType()) {
return;
}
// Otherwise, we're trying to define a value generic parameter with an
// unsupported type right now e.g. 'let N: UInt8'.
errors.push_back(
RequirementError::forInvalidValueGenericType(subjectType,
constraintType,
loc));
} else {
errors.push_back(
RequirementError::forInvalidTypeRequirement(subjectType,
@@ -792,7 +786,8 @@ void swift::rewriting::realizeRequirement(
inferRequirements(secondType, moduleForInference, dc, result);
}
realizeTypeRequirement(dc, firstType, secondType, loc, result, errors);
realizeTypeRequirement(dc, firstType, secondType, loc, result, errors,
/*isFromInheritanceClause*/ false);
break;
}
@@ -845,7 +840,8 @@ void swift::rewriting::realizeInheritedRequirements(
auto *typeRepr = inheritedTypes.getTypeRepr(index);
SourceLoc loc = (typeRepr ? typeRepr->getStartLoc() : SourceLoc());
realizeTypeRequirement(dc, type, inheritedType, loc, result, errors);
realizeTypeRequirement(dc, type, inheritedType, loc, result, errors,
/*isFromInheritanceClause*/ true);
}
// Also check for `SynthesizedProtocolAttr`s with additional constraints added
@@ -856,7 +852,8 @@ void swift::rewriting::realizeInheritedRequirements(
auto inheritedType = attr->getProtocol()->getDeclaredType();
auto loc = attr->getLocation();
realizeTypeRequirement(dc, type, inheritedType, loc, result, errors);
realizeTypeRequirement(dc, type, inheritedType, loc, result, errors,
/*isFromInheritanceClause*/ false);
}
}

View File

@@ -55,7 +55,8 @@ void realizeTypeRequirement(DeclContext *dc,
Type constraintType,
SourceLoc loc,
SmallVectorImpl<StructuralRequirement> &result,
SmallVectorImpl<RequirementError> &errors);
SmallVectorImpl<RequirementError> &errors,
bool isFromInheritanceClause);
void realizeRequirement(DeclContext *dc,
Requirement req, RequirementRepr *reqRepr,

View File

@@ -1,6 +1,8 @@
// RUN: %target-typecheck-verify-swift -disable-availability-checking
protocol P {}
protocol Q {}
class Class {}
func invalid<let N>() { // expected-error {{value generic 'N' must have an explicit value type declared}}
// expected-error@-1 {{generic parameter 'N' is not used in function signature}}
@@ -38,8 +40,6 @@ struct A<let N: Int> {
}
}
extension A where N: P {} // expected-error {{value generic type 'N' cannot conform to protocol 'P'}}
extension A where N == Int {} // expected-error {{cannot constrain value parameter 'N' to be type 'Int'}}
extension A where N == 123 {
@@ -77,7 +77,38 @@ func m(_: GenericWithIntParam<Int, 123>) {} // OK
typealias One = 1 // expected-error {{expected type in type alias declaration}}
struct B<let N: UInt8> {} // expected-error {{'UInt8' is not a supported value type for 'N'}}
// Unsupported type in value type parameter definition.
do {
struct S1<let N: UInt8> {}
// expected-error@-1:20 {{'UInt8' is not a supported value type for 'N'}}
struct S2<let N: Any> {}
// expected-error@-1:20 {{'Any' is not a supported value type for 'N'}}
struct S3<let N: AnyObject> {}
// expected-error@-1:20 {{'AnyObject' is not a supported value type for 'N'}}
struct S4<let N: Class> {}
// expected-error@-1:20 {{'Class' is not a supported value type for 'N'}}
struct S5<let N: P> {}
// expected-error@-1:20 {{'P' is not a supported value type for 'N'}}
struct S6<let N: P & Q> {}
// expected-error@-1:20 {{'P & Q' is not a supported value type for 'N'}}
struct S7<let N: ~Copyable> {}
// expected-error@-1:20 {{'~Copyable' is not a supported value type for 'N'}}
}
// Subtype constraint on value type parameter.
struct S1<let x: Int> where x: Class, x: P, x: P & Q, x: Int, x: ~Copyable {}
// expected-error@-1:30 {{cannot use type constraint with generic value parameter 'x'}}
// expected-error@-2:40 {{cannot use type constraint with generic value parameter 'x'}}
// expected-error@-3:46 {{cannot use type constraint with generic value parameter 'x'}}
// expected-error@-4:56 {{cannot use type constraint with generic value parameter 'x'}}
// expected-error@-5:64 {{cannot use type constraint with generic value parameter 'x'}}
extension S1 where x: Class, x: P, x: P & Q, x: Int, x: ~Copyable {}
// expected-error@-1:21 {{cannot use type constraint with generic value parameter 'x'}}
// expected-error@-2:31 {{cannot use type constraint with generic value parameter 'x'}}
// expected-error@-3:37 {{cannot use type constraint with generic value parameter 'x'}}
// expected-error@-4:47 {{cannot use type constraint with generic value parameter 'x'}}
// expected-error@-5:55 {{cannot use type constraint with generic value parameter 'x'}}
struct C<let N: Int, let M: Int> {}

View File

@@ -1,5 +1,5 @@
// {"kind":"emit-ir","original":"493cc9db","signature":"(anonymous namespace)::TypeContextDescriptorBuilderBase<(anonymous namespace)::StructContextDescriptorBuilder, swift::StructDecl>::emit()"}
// RUN: not --crash %target-swift-frontend -emit-ir %s
// RUN: not %target-swift-frontend -emit-ir %s
class a<b> {
}
@available(SwiftStdlib 6.2, *)