diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index bf0a72ee252..1e67a2b7a49 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -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, diff --git a/lib/AST/RequirementMachine/Diagnostics.cpp b/lib/AST/RequirementMachine/Diagnostics.cpp index 45d79028831..e57299aefd6 100644 --- a/lib/AST/RequirementMachine/Diagnostics.cpp +++ b/lib/AST/RequirementMachine/Diagnostics.cpp @@ -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; } diff --git a/lib/AST/RequirementMachine/Diagnostics.h b/lib/AST/RequirementMachine/Diagnostics.h index 04fb990b5d4..d5721a0f631 100644 --- a/lib/AST/RequirementMachine/Diagnostics.h +++ b/lib/AST/RequirementMachine/Diagnostics.h @@ -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 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, diff --git a/lib/AST/RequirementMachine/RequirementLowering.cpp b/lib/AST/RequirementMachine/RequirementLowering.cpp index 81115cec124..3203d8e93ac 100644 --- a/lib/AST/RequirementMachine/RequirementLowering.cpp +++ b/lib/AST/RequirementMachine/RequirementLowering.cpp @@ -389,15 +389,6 @@ static void desugarConformanceRequirement( // Fast path. if (constraintType->is()) { - // 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 &result, - SmallVectorImpl &errors) { + SmallVectorImpl &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. ``. + 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 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(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); } } diff --git a/lib/AST/RequirementMachine/RequirementLowering.h b/lib/AST/RequirementMachine/RequirementLowering.h index e83a9d13374..f0626beaaf9 100644 --- a/lib/AST/RequirementMachine/RequirementLowering.h +++ b/lib/AST/RequirementMachine/RequirementLowering.h @@ -55,7 +55,8 @@ void realizeTypeRequirement(DeclContext *dc, Type constraintType, SourceLoc loc, SmallVectorImpl &result, - SmallVectorImpl &errors); + SmallVectorImpl &errors, + bool isFromInheritanceClause); void realizeRequirement(DeclContext *dc, Requirement req, RequirementRepr *reqRepr, diff --git a/test/Sema/value_generics.swift b/test/Sema/value_generics.swift index c29c343d74c..81904712f67 100644 --- a/test/Sema/value_generics.swift +++ b/test/Sema/value_generics.swift @@ -1,6 +1,8 @@ // RUN: %target-typecheck-verify-swift -disable-availability-checking protocol P {} +protocol Q {} +class Class {} func invalid() { // 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 { } } -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) {} // OK typealias One = 1 // expected-error {{expected type in type alias declaration}} -struct B {} // expected-error {{'UInt8' is not a supported value type for 'N'}} +// Unsupported type in value type parameter definition. +do { + struct S1 {} + // expected-error@-1:20 {{'UInt8' is not a supported value type for 'N'}} + struct S2 {} + // expected-error@-1:20 {{'Any' is not a supported value type for 'N'}} + struct S3 {} + // expected-error@-1:20 {{'AnyObject' is not a supported value type for 'N'}} + struct S4 {} + // expected-error@-1:20 {{'Class' is not a supported value type for 'N'}} + struct S5 {} + // expected-error@-1:20 {{'P' is not a supported value type for 'N'}} + struct S6 {} + // expected-error@-1:20 {{'P & Q' is not a supported value type for 'N'}} + struct S7 {} + // expected-error@-1:20 {{'~Copyable' is not a supported value type for 'N'}} +} + +// Subtype constraint on value type parameter. + +struct S1 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 {} diff --git a/validation-test/compiler_crashers_2/43f7a6012f6a255a.swift b/validation-test/compiler_crashers_2_fixed/43f7a6012f6a255a.swift similarity index 83% rename from validation-test/compiler_crashers_2/43f7a6012f6a255a.swift rename to validation-test/compiler_crashers_2_fixed/43f7a6012f6a255a.swift index dd33a021612..daa05bf65a9 100644 --- a/validation-test/compiler_crashers_2/43f7a6012f6a255a.swift +++ b/validation-test/compiler_crashers_2_fixed/43f7a6012f6a255a.swift @@ -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 { } @available(SwiftStdlib 6.2, *)