Skip to content

Commit 3e9c463

Browse files
committed
Add some new diagnostics and tests
1 parent 75c2cbf commit 3e9c463

File tree

8 files changed

+190
-19
lines changed

8 files changed

+190
-19
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3002,16 +3002,6 @@ WARNING(associated_type_not_usable_from_inline_warn,none,
30023002
"'@usableFromInline' protocol should be '@usableFromInline' or public",
30033003
(unsigned))
30043004

3005-
ERROR(invalid_value_variable_generic,none,
3006-
"%0 requires that %1 must be a valid value for %2",
3007-
(Type, Type, Type))
3008-
NOTE(invalid_value_variable_generic_requirement,none,
3009-
"requirement specified as %0 == %1%2",
3010-
(Type, Type, StringRef))
3011-
ERROR(cannot_pass_type_for_value_generic,none,
3012-
"cannot pass type %1 as a value for generic value of %2",
3013-
(Type, Type, Type))
3014-
30153005
NOTE(bad_associated_type_deduction,none,
30163006
"unable to infer associated type %0 for protocol %1",
30173007
(const AssociatedTypeDecl *, const ProtocolDecl *))
@@ -4751,9 +4741,6 @@ NOTE(add_parens_to_type,none,
47514741
NOTE(add_self_to_type,none,
47524742
"use '.self' to reference the type object", ())
47534743

4754-
ERROR(cannot_self_value_generic,none,
4755-
"cannot reference '.self' on value generic parameter %0", (Type))
4756-
47574744
WARNING(warn_unqualified_access,none,
47584745
"use of %0 treated as a reference to %1 in %kind2",
47594746
(Identifier, DescriptiveDeclKind, const ValueDecl *))
@@ -8011,5 +7998,27 @@ WARNING(reference_to_unsafe_typed_decl,none,
80117998
NOTE(unsafe_decl_here,none,
80127999
"unsafe %kindbase0 declared here", (const ValueDecl *))
80138000

8001+
//===----------------------------------------------------------------------===//
8002+
// MARK: Value Generics
8003+
//===----------------------------------------------------------------------===//
8004+
8005+
ERROR(invalid_value_value_generic,none,
8006+
"%0 requires that %1 must be a valid value for %2",
8007+
(Type, Type, Type))
8008+
NOTE(invalid_value_value_generic_requirement,none,
8009+
"requirement specified as %0 == %1%2",
8010+
(Type, Type, StringRef))
8011+
ERROR(cannot_pass_type_for_value_generic,none,
8012+
"cannot pass type %1 as a value for generic value of %2",
8013+
(Type, Type, Type))
8014+
ERROR(value_type_used_in_type_parameter,none,
8015+
"cannot use value type %0 for generic argument %1", (Type, Type))
8016+
ERROR(cannot_self_value_generic,none,
8017+
"cannot reference '.self' on value generic parameter %0", (Type))
8018+
ERROR(invalid_value_type_value_generic,none,
8019+
"%0 is not a supported value type for %1", (Type, Type))
8020+
ERROR(invalid_value_generic_conformance,none,
8021+
"value generic type %0 cannot conform to protocol %1", (Type, Type))
8022+
80148023
#define UNDEFINE_DIAGNOSTIC_MACROS
80158024
#include "DefineDiagnosticMacros.h"

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5693,11 +5693,15 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
56935693
} else if (auto param = dyn_cast<GenericTypeParamType>(T.getPointer())) {
56945694
if (param->isParameterPack())
56955695
return false;
5696+
if (param->isValue())
5697+
return false;
56965698
} else if (auto archetype = dyn_cast<ArchetypeType>(T.getPointer())) {
56975699
if (isa<PackArchetypeType>(archetype))
56985700
return false;
56995701
if (Options.PrintForSIL && isa<LocalArchetypeType>(archetype))
57005702
return false;
5703+
if (archetype->getValueType())
5704+
return false;
57015705
}
57025706
return T->hasSimpleTypeRepr();
57035707
}

lib/AST/RequirementMachine/Diagnostics.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,30 @@ bool swift::rewriting::diagnoseRequirementErrors(
225225
diagnosedError = true;
226226
break;
227227
}
228+
229+
case RequirementError::Kind::InvalidValueGenericType: {
230+
auto req = error.getRequirement();
231+
232+
if (req.hasError())
233+
break;
234+
235+
ctx.Diags.diagnose(loc, diag::invalid_value_type_value_generic,
236+
req.getSecondType(), req.getFirstType());
237+
diagnosedError = true;
238+
break;
239+
}
240+
241+
case RequirementError::Kind::InvalidValueGenericConformance: {
242+
auto req = error.getRequirement();
243+
244+
if (req.hasError())
245+
break;
246+
247+
ctx.Diags.diagnose(loc, diag::invalid_value_generic_conformance,
248+
req.getFirstType(), req.getSecondType());
249+
diagnosedError = true;
250+
break;
251+
}
228252
}
229253
}
230254

lib/AST/RequirementMachine/Diagnostics.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ struct RequirementError {
5353
RecursiveRequirement,
5454
/// A not-yet-supported same-element requirement, e.g. each T == Int.
5555
UnsupportedSameElement,
56+
/// An unexpected value type used in a value generic,
57+
/// e.g. 'let N: String'.
58+
InvalidValueGenericType,
59+
/// A value generic type was used to conform to a protocol,
60+
/// e.g. 'where N: P' where N == 'let N: Int' and P is some protocol.
61+
InvalidValueGenericConformance,
5662
} kind;
5763

5864
private:
@@ -149,6 +155,16 @@ struct RequirementError {
149155
static RequirementError forSameElement(Requirement req, SourceLoc loc) {
150156
return {Kind::UnsupportedSameElement, req, loc};
151157
}
158+
159+
static RequirementError forInvalidValueGenericType(Requirement req,
160+
SourceLoc loc) {
161+
return {Kind::InvalidValueGenericType, req, loc};
162+
}
163+
164+
static RequirementError forInvalidValueGenericConformance(Requirement req,
165+
SourceLoc loc) {
166+
return {Kind::InvalidValueGenericConformance, req, loc};
167+
}
152168
};
153169

154170
/// Policy for the fixit that transforms 'T : S' where 'S' is not a protocol

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,12 @@ static void desugarConformanceRequirement(
337337
// Fast path.
338338
if (constraintType->is<ProtocolType>()) {
339339
if (req.getFirstType()->isTypeParameter()) {
340+
// Value generic types cannot conform to protocols.
341+
if (req.getFirstType()->getAs<GenericTypeParamType>()->isValue()) {
342+
errors.push_back(RequirementError::forInvalidValueGenericConformance(req, loc));
343+
return;
344+
}
345+
340346
result.push_back(req);
341347
return;
342348
}
@@ -419,6 +425,12 @@ static void desugarValueRequirement(Requirement req, SourceLoc loc,
419425
SmallVectorImpl<Requirement> &result,
420426
SmallVectorImpl<InverseRequirement> &inverses,
421427
SmallVectorImpl<RequirementError> &errors) {
428+
429+
if (!req.getSecondType()->isLegalValueGenericType()) {
430+
errors.push_back(RequirementError::forInvalidValueGenericType(req, loc));
431+
return;
432+
}
433+
422434
if (req.getFirstType()->isTypeParameter()) {
423435
result.push_back(req);
424436
return;
@@ -531,9 +543,7 @@ static void realizeTypeRequirement(TypeDecl *decl, DeclContext *dc,
531543
result.push_back({Requirement(RequirementKind::Superclass,
532544
subjectType, constraintType),
533545
loc});
534-
} else if (gpDecl &&
535-
gpDecl->isValue() &&
536-
constraintType->isLegalValueGenericType()) {
546+
} else if (gpDecl && gpDecl->isValue()) {
537547
result.push_back({Requirement(RequirementKind::Value,
538548
subjectType, constraintType),
539549
loc});
@@ -689,6 +699,10 @@ struct InferRequirementsWalker : public TypeWalker {
689699
if (skipRequirement(rawReq, decl))
690700
continue;
691701

702+
if (rawReq.getKind() == RequirementKind::Value) {
703+
continue;
704+
}
705+
692706
reqs.push_back({rawReq.subst(subMap), SourceLoc()});
693707
}
694708

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -964,11 +964,11 @@ void TypeChecker::diagnoseRequirementFailure(
964964

965965
case RequirementKind::Value:
966966
if (substReq.getFirstType()->is<IntegerType>()) {
967-
diagnostic = diag::invalid_value_variable_generic;
968-
diagnosticNote = diag::invalid_value_variable_generic_requirement;
967+
diagnostic = diag::invalid_value_value_generic;
968+
diagnosticNote = diag::invalid_value_value_generic_requirement;
969969
} else {
970970
diagnostic = diag::cannot_pass_type_for_value_generic;
971-
diagnosticNote = diag::invalid_value_variable_generic_requirement;
971+
diagnosticNote = diag::invalid_value_value_generic_requirement;
972972
}
973973

974974
break;

lib/Sema/TypeCheckType.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4762,6 +4762,37 @@ TypeResolver::resolveDeclRefTypeRepr(DeclRefTypeRepr *repr,
47624762
return ErrorType::get(result->getASTContext());
47634763
}
47644764

4765+
// Diagnose an error if an IntegerType or GenericTypeParamType who is a value
4766+
// is being used as a type parameter instead of a value parameter.
4767+
//
4768+
// FIXME: This runs through every bound generic type, is there a better way
4769+
// of doing this or perhaps add a quicker check so that we aren't doing this
4770+
// for all types..?
4771+
if (auto generic = result->getAs<BoundGenericType>()) {
4772+
auto subs = generic->getContextSubstitutionMap();
4773+
auto replacements = subs.getReplacementTypes();
4774+
auto params = subs.getGenericSignature().getGenericParams();
4775+
4776+
for (auto p : llvm::zip(params, replacements)) {
4777+
auto param = std::get<0>(p);
4778+
auto replacement = std::get<1>(p);
4779+
4780+
if (replacement->is<IntegerType>() && !param->isValue()) {
4781+
result->getASTContext().Diags.diagnose(repr->getLoc(),
4782+
diag::value_type_used_in_type_parameter, replacement, param);
4783+
return ErrorType::get(result->getASTContext());
4784+
}
4785+
4786+
if (replacement->is<GenericTypeParamType>() &&
4787+
replacement->getAs<GenericTypeParamType>()->isValue() &&
4788+
!param->isValue()) {
4789+
result->getASTContext().Diags.diagnose(repr->getLoc(),
4790+
diag::value_type_used_in_type_parameter, replacement, param);
4791+
return ErrorType::get(result->getASTContext());
4792+
}
4793+
}
4794+
}
4795+
47654796
if (auto moduleTy = result->getAs<ModuleType>()) {
47664797
// Allow module types only if flag is specified.
47674798
if (options.contains(TypeResolutionFlags::AllowModule))

test/Sema/value_generics.swift

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature NonescapableTypes
2+
3+
protocol P {}
4+
5+
struct A<let N: Int> { // expected-note {{requirement specified as 'let N' == 'Int' [with N = T]}}
6+
// expected-note@-1 {{requirement specified as 'let N' == 'Int' [with N = Int]}}
7+
var int: Int {
8+
N // OK
9+
}
10+
11+
var uint: UInt {
12+
N // expected-error {{cannot convert return expression of type '(let N).Type' to return type 'UInt'}}
13+
}
14+
}
15+
16+
extension A where N: P {} // expected-error {{value generic type 'let N' cannot conform to protocol 'P'}}
17+
18+
func b(with a: A<123>) {} // OK
19+
func c<let M: Int>(with a: A<M>) {} // OK
20+
func d<T>(with a: A<T>) {} // expected-error {{cannot pass type 'T' as a value for generic value of 'Int'}}
21+
func e(with a: A<Int>) {} // expected-error {{cannot pass type 'Int' as a value for generic value of 'Int'}}
22+
23+
struct Generic<T: ~Copyable & ~Escapable> {}
24+
25+
func f(with generic: Generic<123>) {} // expected-error {{cannot use value type '123' for generic argument 'T'}}
26+
func g<let N: Int>(with generic: Generic<N>) {} // expected-error {{cannot use value type 'let N' for generic argument 'T'}}
27+
28+
struct B<let N: UInt8> {} // expected-error {{'UInt8' is not a supported value type for 'let N'}}
29+
30+
struct C<let N: Int, let M: Int> {}
31+
32+
extension C where N == 123 { // expected-note {{where 'let N' = '0'}}
33+
// expected-note@-1 {{where 'let N' = '0'}}
34+
// expected-note@-2 {{where 'let N' = 'let T'}}
35+
func nIs123() {}
36+
}
37+
38+
extension C where M == 321 { // expected-note {{where 'let M' = '0'}}
39+
// expected-note@-1 {{where 'let M' = '0'}}
40+
// expected-note@-2 {{where 'let M' = 'let T'}}
41+
func mIs123() {}
42+
}
43+
44+
extension C where N == M { // expected-note {{where 'let N' = '123', 'let M' = '0'}}
45+
// expected-note@-1 {{where 'let N' = '0', 'let M' = '321'}}
46+
func nAndMAreBothEqual() {}
47+
}
48+
49+
func testC1(with c: C<0, 0>) {
50+
c.nIs123() // expected-error {{referencing instance method 'nIs123()' on 'C' requires the types '0' and '123' be equivalent}}
51+
c.mIs123() // expected-error {{referencing instance method 'mIs123()' on 'C' requires the types '0' and '321' be equivalent}}
52+
c.nAndMAreBothEqual() // OK
53+
}
54+
55+
func testC2(with c: C<123, 0>) {
56+
c.nIs123() // OK
57+
c.mIs123() // expected-error {{referencing instance method 'mIs123()' on 'C' requires the types '0' and '321' be equivalent}}
58+
c.nAndMAreBothEqual() // expected-error {{referencing instance method 'nAndMAreBothEqual()' on 'C' requires the types '123' and '0' be equivalent}}
59+
}
60+
61+
func testC3(with c: C<0, 321>) {
62+
c.nIs123() // expected-error {{referencing instance method 'nIs123()' on 'C' requires the types '0' and '123' be equivalent}}
63+
c.mIs123() // OK
64+
c.nAndMAreBothEqual() // expected-error {{referencing instance method 'nAndMAreBothEqual()' on 'C' requires the types '0' and '321' be equivalent}}
65+
}
66+
67+
func testC4<let T: Int>(with c: C<T, T>) {
68+
c.nIs123() // expected-error {{referencing instance method 'nIs123()' on 'C' requires the types 'let T' and '123' be equivalent}}
69+
c.mIs123() // expected-error {{referencing instance method 'mIs123()' on 'C' requires the types 'let T' and '321' be equivalent}}
70+
c.nAndMAreBothEqual() // OK
71+
}
72+
73+
struct D<let N: Int & P> {} // expected-error {{non-protocol, non-class type 'Int' cannot be used within a protocol-constrained type}}

0 commit comments

Comments
 (0)