Skip to content

Commit 718bba4

Browse files
authored
Merge pull request #76404 from Azoy/integer-type-parsing-fixes
[Parse] Fix type parsing when preceded by '-'
2 parents ad94d55 + 6f83e3c commit 718bba4

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
@@ -8012,12 +8012,6 @@ NOTE(unsafe_decl_here,none,
80128012
// MARK: Value Generics
80138013
//===----------------------------------------------------------------------===//
80148014

8015-
ERROR(invalid_value_value_generic,none,
8016-
"%0 requires that %1 must be a valid value for %2",
8017-
(Type, Type, Type))
8018-
NOTE(invalid_value_value_generic_requirement,none,
8019-
"requirement specified as %0 == %1%2",
8020-
(Type, Type, StringRef))
80218015
ERROR(cannot_pass_type_for_value_generic,none,
80228016
"cannot pass type %0 as a value for generic value %1", (Type, Type))
80238017
ERROR(value_type_used_in_type_parameter,none,
@@ -8039,6 +8033,8 @@ ERROR(value_generics_missing_feature,none,
80398033
ERROR(availability_value_generic_type_only_version_newer, none,
80408034
"values in generic types are only available in %0 %1 or newer",
80418035
(StringRef, llvm::VersionTuple))
8036+
ERROR(invalid_value_for_type_same_type,none,
8037+
"cannot constrain type parameter %0 to be integer %1", (Type, Type))
80428038

80438039
#define UNDEFINE_DIAGNOSTIC_MACROS
80448040
#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
@@ -175,9 +175,9 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
175175
tildeLoc = consumeToken();
176176
}
177177

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

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

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