Skip to content

Commit 6f83e3c

Browse files
committed
Fix type parsing when preceeded by '-'
1 parent 080c20c commit 6f83e3c

File tree

7 files changed

+90
-12
lines changed

7 files changed

+90
-12
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8002,12 +8002,6 @@ NOTE(unsafe_decl_here,none,
80028002
// MARK: Value Generics
80038003
//===----------------------------------------------------------------------===//
80048004

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))
80118005
ERROR(cannot_pass_type_for_value_generic,none,
80128006
"cannot pass type %0 as a value for generic value %1", (Type, Type))
80138007
ERROR(value_type_used_in_type_parameter,none,
@@ -8029,6 +8023,8 @@ ERROR(value_generics_missing_feature,none,
80298023
ERROR(availability_value_generic_type_only_version_newer, none,
80308024
"values in generic types are only available in %0 %1 or newer",
80318025
(StringRef, llvm::VersionTuple))
8026+
ERROR(invalid_value_for_type_same_type,none,
8027+
"cannot constrain type parameter %0 to be integer %1", (Type, Type))
80328028

80338029
#define UNDEFINE_DIAGNOSTIC_MACROS
80348030
#include "DefineDiagnosticMacros.h"

lib/AST/RequirementMachine/Diagnostics.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,18 @@ bool swift::rewriting::diagnoseRequirementErrors(
261261
diagnosedError = true;
262262
break;
263263
}
264+
265+
case RequirementError::Kind::InvalidValueForTypeSameType: {
266+
auto req = error.getRequirement();
267+
268+
if (req.hasError())
269+
break;
270+
271+
ctx.Diags.diagnose(loc, diag::invalid_value_for_type_same_type,
272+
req.getFirstType(), req.getSecondType());
273+
diagnosedError = true;
274+
break;
275+
}
264276
}
265277
}
266278

lib/AST/RequirementMachine/Diagnostics.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ struct RequirementError {
6262
/// A value generic type was used to same-type to an unrelated type,
6363
/// e.g. 'where N == Int' where N == 'let N: Int'.
6464
InvalidValueGenericSameType,
65+
/// A value type, either an integer '123' or a value generic parameter 'N',
66+
/// was used to same type a regular type parameter, e.g. 'T == 123'.
67+
InvalidValueForTypeSameType,
6568
} kind;
6669

6770
private:
@@ -177,6 +180,13 @@ struct RequirementError {
177180
Requirement requirement(RequirementKind::Conformance, subjectType, constraint);
178181
return {Kind::InvalidValueGenericSameType, requirement, loc};
179182
}
183+
184+
static RequirementError forInvalidValueForTypeSameType(Type subjectType,
185+
Type constraint,
186+
SourceLoc loc) {
187+
Requirement requirement(RequirementKind::Conformance, subjectType, constraint);
188+
return {Kind::InvalidValueForTypeSameType, requirement, loc};
189+
}
180190
};
181191

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

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,18 @@ static void desugarSameTypeRequirement(
250250
}
251251
}
252252

253+
if (!firstType->isValueParameter() && secondType->is<IntegerType>()) {
254+
errors.push_back(RequirementError::forInvalidValueForTypeSameType(
255+
sugaredFirstType, secondType, loc));
256+
return true;
257+
}
258+
259+
if (!secondType->isValueParameter() && firstType->is<IntegerType>()) {
260+
errors.push_back(RequirementError::forInvalidValueForTypeSameType(
261+
secondType, sugaredFirstType, loc));
262+
return true;
263+
}
264+
253265
if (firstType->isTypeParameter() && secondType->isTypeParameter()) {
254266
result.emplace_back(kind, sugaredFirstType, secondType);
255267
return true;

lib/Parse/ParseType.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,9 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
176176
tildeLoc = consumeToken();
177177
}
178178

179-
// Eat any '-' preceding the type.
179+
// Eat any '-' preceding integer literals.
180180
SourceLoc minusLoc;
181-
if (Tok.isMinus()) {
181+
if (Tok.isMinus() && peekToken().is(tok::integer_literal)) {
182182
minusLoc = consumeToken();
183183
}
184184

@@ -1588,13 +1588,26 @@ bool Parser::canParseType() {
15881588
return false;
15891589
break;
15901590
case tok::oper_prefix:
1591-
if (Tok.getText() != "~" && Tok.getText() != "-") {
1591+
if (!Tok.isTilde() && !Tok.isMinus()) {
15921592
return false;
15931593
}
15941594

1595-
consumeToken();
1596-
if (!canParseTypeIdentifier())
1597-
return false;
1595+
// '~' can only appear before type identifiers like '~Copyable'.
1596+
if (Tok.isTilde()) {
1597+
consumeToken();
1598+
1599+
if (!canParseTypeIdentifier())
1600+
return false;
1601+
}
1602+
1603+
// '-' can only appear before integers being used as types like '-123'.
1604+
if (Tok.isMinus()) {
1605+
consumeToken();
1606+
1607+
if (!Tok.is(tok::integer_literal))
1608+
return false;
1609+
}
1610+
15981611
break;
15991612
case tok::kw_protocol:
16001613
return canParseOldStyleProtocolComposition();

test/Parse/integer_types.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
let a: 123 // expected-error {{integer unexpectedly used in a type position}}
4+
5+
let b: -123 // expected-error {{integer unexpectedly used in a type position}}
6+
7+
let c: -Int // expected-error {{expected type}}
8+
// expected-error@-1 {{consecutive statements on a line must be separated by ';'}}
9+
// expected-error@-2 {{unary operator '-' cannot be applied to an operand of type 'Int.Type'}}
10+
11+
struct Generic<T> {} // expected-note {{'T' declared as parameter to type 'Generic'}}
12+
// expected-note@-1 {{'T' declared as parameter to type 'Generic'}}
13+
14+
extension Generic where T == 123 {} // expected-error {{cannot constrain type parameter 'T' to be integer '123'}}
15+
16+
extension Generic where T == -123 {} // expected-error {{cannot constrain type parameter 'T' to be integer '-123'}}
17+
18+
extension Generic where T == -Int {} // expected-error {{expected type}}
19+
// expected-error@-1 {{expected '{' in extension}}
20+
21+
let d = Generic<123>.self // expected-error {{integer unexpectedly used in a type position}}
22+
23+
// FIXME: This should at least be parsable...?
24+
let e = Generic<-123>.self // expected-error {{generic parameter 'T' could not be inferred}}
25+
// expected-error@-1 {{missing whitespace between '<' and '-' operators}}
26+
// expected-error@-2 {{'>' is not a postfix unary operator}}
27+
// expected-note@-3 {{explicitly specify the generic arguments to fix this issue}}
28+
29+
let f = Generic<-Int>.self // expected-error {{generic parameter 'T' could not be inferred}}
30+
// expected-error@-1 {{missing whitespace between '<' and '-' operators}}
31+
// expected-error@-2 {{'>' is not a postfix unary operator}}
32+
// expected-note@-3 {{explicitly specify the generic arguments to fix this issue}}

test/Sema/value_generics.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ func e(with a: A<Int>) {} // expected-error {{cannot pass type 'Int' as a value
4848
struct Generic<T: ~Copyable & ~Escapable> {}
4949
struct GenericWithIntParam<T: ~Copyable & ~Escapable, let N: Int> {}
5050

51+
extension Generic where T == 123 {} // expected-error {{cannot constrain type parameter 'T' to be integer '123'}}
52+
extension Generic where T == 123.Type {} // expected-error {{integer unexpectedly used in a type position}}
53+
5154
func f(_: Generic<123>) {} // expected-error {{integer unexpectedly used in a type position}}
5255
func g<let N: Int>(_: Generic<N>) {} // expected-error {{cannot use value type 'N' for generic argument 'T'}}
5356
func h(_: (Int, 123)) {} // expected-error {{integer unexpectedly used in a type position}}

0 commit comments

Comments
 (0)