Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -8592,8 +8592,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,
Expand Down
6 changes: 3 additions & 3 deletions lib/AST/RequirementMachine/Diagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
15 changes: 9 additions & 6 deletions lib/AST/RequirementMachine/Diagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -176,9 +176,12 @@ struct RequirementError {
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,
Expand Down
55 changes: 26 additions & 29 deletions lib/AST/RequirementMachine/RequirementLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand All @@ -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);
}
}

Expand Down
3 changes: 2 additions & 1 deletion lib/AST/RequirementMachine/RequirementLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
37 changes: 34 additions & 3 deletions test/Sema/value_generics.swift
Original file line number Diff line number Diff line change
@@ -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}}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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> {}

Expand Down
Original file line number Diff line number Diff line change
@@ -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, *)
Expand Down