Skip to content

[Parse] Restrict parsing integer types in certain contexts #76553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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
5 changes: 5 additions & 0 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,11 @@ class Parser {
ParserResult<TypeRepr> parseTypeSimple(
Diag<> MessageID, ParseTypeReason reason);

ParserResult<TypeRepr> parseTypeOrValue();
ParserResult<TypeRepr> parseTypeOrValue(Diag<> MessageID,
ParseTypeReason reason = ParseTypeReason::Unspecified,
bool fromASTGen = false);

/// Parse layout constraint.
LayoutConstraint parseLayoutConstraint(Identifier LayoutConstraintID);

Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4116,7 +4116,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
return makeParserSuccess();
}

auto countType = parseType(diag::expected_type);
auto countType = parseTypeOrValue(diag::expected_type);
if (countType.isNull()) {
return makeParserSuccess();
}
Expand Down
8 changes: 6 additions & 2 deletions lib/Parse/ParseGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,9 @@ ParserStatus Parser::parseGenericWhereClause(

// Parse the leading type. It doesn't necessarily have to be just a type
// identifier if we're dealing with a same-type constraint.
ParserResult<TypeRepr> FirstType = parseType();
//
// Note: This can be a value type, e.g. '123 == N' or 'N == 123'.
ParserResult<TypeRepr> FirstType = parseTypeOrValue();

if (FirstType.hasCodeCompletion()) {
Status.setHasCodeCompletionAndIsError();
Expand Down Expand Up @@ -377,7 +379,9 @@ ParserStatus Parser::parseGenericWhereClause(
SourceLoc EqualLoc = consumeToken();

// Parse the second type.
ParserResult<TypeRepr> SecondType = parseType();
//
// Note: This can be a value type, e.g. '123 == N' or 'N == 123'.
ParserResult<TypeRepr> SecondType = parseTypeOrValue();
Status |= SecondType;
if (SecondType.isNull())
SecondType = makeParserResult(ErrorTypeRepr::create(Context, PreviousLoc));
Expand Down
40 changes: 27 additions & 13 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,6 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
tildeLoc = consumeToken();
}

// Eat any '-' preceding integer literals.
SourceLoc minusLoc;
if (Tok.isMinus() && peekToken().is(tok::integer_literal)) {
minusLoc = consumeToken();
}

switch (Tok.getKind()) {
case tok::kw_Self:
case tok::identifier:
Expand Down Expand Up @@ -237,12 +231,6 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
}
return makeParserCodeCompletionResult<TypeRepr>(
ErrorTypeRepr::create(Context, consumeToken(tok::code_complete)));
case tok::integer_literal: {
auto text = copyAndStripUnderscores(Tok.getText());
auto loc = consumeToken(tok::integer_literal);
ty = makeParserResult(new (Context) IntegerTypeRepr(text, loc, minusLoc));
break;
}
case tok::l_square: {
ty = parseTypeCollection();
break;
Expand Down Expand Up @@ -739,7 +727,8 @@ ParserStatus Parser::parseGenericArguments(SmallVectorImpl<TypeRepr *> &Args,
// variadic generic types.
if (!startsWithGreater(Tok)) {
while (true) {
ParserResult<TypeRepr> Ty = parseType(diag::expected_type);
// Note: This can be a value type, e.g. 'Vector<3, Int>'.
ParserResult<TypeRepr> Ty = parseTypeOrValue(diag::expected_type);
if (Ty.isNull() || Ty.hasCodeCompletion()) {
// Skip until we hit the '>'.
RAngleLoc = skipUntilGreaterInTypeList();
Expand Down Expand Up @@ -1481,6 +1470,31 @@ Parser::parseTypeImplicitlyUnwrappedOptional(ParserResult<TypeRepr> base) {
return makeParserResult(ParserStatus(base), TyR);
}

ParserResult<TypeRepr> Parser::parseTypeOrValue() {
return parseTypeOrValue(diag::expected_type);
}

ParserResult<TypeRepr> Parser::parseTypeOrValue(Diag<> MessageID,
ParseTypeReason reason,
bool fromASTGen) {
// Eat any '-' preceding integer literals.
SourceLoc minusLoc;
if (Tok.isMinus() && peekToken().is(tok::integer_literal)) {
minusLoc = consumeToken();
}

// Attempt to parse values first. Right now the only value that can be parsed
// as a type are integers.
if (Tok.is(tok::integer_literal)) {
auto text = copyAndStripUnderscores(Tok.getText());
auto loc = consumeToken(tok::integer_literal);
return makeParserResult(new (Context) IntegerTypeRepr(text, loc, minusLoc));
}

// Otherwise, attempt to parse a regular type.
return parseType(MessageID, reason, fromASTGen);
}

//===----------------------------------------------------------------------===//
// Speculative type list parsing
//===----------------------------------------------------------------------===//
Expand Down
38 changes: 37 additions & 1 deletion lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,42 @@ bool SILParser::parseASTType(CanType &result,
return false;
}

bool SILParser::parseASTTypeOrValue(CanType &result,
GenericSignature genericSig,
GenericParamList *genericParams,
bool forceContextualType) {
auto parsedType = P.parseTypeOrValue();
if (parsedType.isNull()) return true;

// If we weren't given a specific generic context to resolve the type
// within, use the contextual generic parameters and always produce
// a contextual type. Otherwise, produce a contextual type only if
// we were asked for one.
bool wantContextualType = forceContextualType;
if (!genericSig) {
genericSig = ContextGenericSig;
wantContextualType = true;
}
if (genericParams == nullptr)
genericParams = ContextGenericParams;

bindSILGenericParams(parsedType.get());

auto resolvedType = performTypeResolution(
parsedType.get(), /*isSILType=*/false, genericSig, genericParams);
if (wantContextualType && genericSig) {
resolvedType = genericSig.getGenericEnvironment()
->mapTypeIntoContext(resolvedType);
}

if (resolvedType->hasError())
return true;

result = resolvedType->getCanonicalType();

return false;
}

void SILParser::bindSILGenericParams(TypeRepr *TyR) {
// Resolve the generic environments for parsed generic function and box types.
class HandleSILGenericParamsWalker : public ASTWalker {
Expand Down Expand Up @@ -3097,7 +3133,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
CanType paramType;
if (parseSILType(Ty) ||
parseVerbatim("for") ||
parseASTType(paramType))
parseASTTypeOrValue(paramType))
return true;

ResultVal = B.createTypeValue(InstLoc, Ty, paramType);
Expand Down
5 changes: 5 additions & 0 deletions lib/SIL/Parser/SILParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ class SILParser {
return false;
}

bool parseASTTypeOrValue(CanType &result,
GenericSignature genericSig = GenericSignature(),
GenericParamList *genericParams = nullptr,
bool forceContextualType = false);

std::optional<StringRef>
parseOptionalAttribute(ArrayRef<StringRef> expected) {
// We parse here @ <identifier>.
Expand Down
24 changes: 22 additions & 2 deletions test/Parse/integer_types.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// RUN: %target-typecheck-verify-swift

let a: 123 // expected-error {{integer unexpectedly used in a type position}}
let a: 123 // expected-error {{consecutive statements on a line must be separated by ';'}}
// expected-error@-1 {{expected type}}
// expected-warning@-2 {{integer literal is unused}}

let b: -123 // expected-error {{integer unexpectedly used in a type position}}
let b: -123 // expected-error {{consecutive statements on a line must be separated by ';'}}
// expected-error@-1 {{expected type}}
// expected-warning@-2 {{integer literal is unused}}

let c: -Int // expected-error {{expected type}}
// expected-error@-1 {{consecutive statements on a line must be separated by ';'}}
Expand Down Expand Up @@ -30,3 +34,19 @@ let f = Generic<-Int>.self // expected-error {{generic parameter 'T' could not b
// expected-error@-1 {{missing whitespace between '<' and '-' operators}}
// expected-error@-2 {{'>' is not a postfix unary operator}}
// expected-note@-3 {{explicitly specify the generic arguments to fix this issue}}

let g: 123.Type // expected-error {{consecutive statements on a line must be separated by ';'}}
// expected-error@-1 {{expected type}}
// expected-error@-2 {{value of type 'Int' has no member 'Type'}}

let h: 123.Protocol // expected-error {{consecutive statements on a line must be separated by ';'}}
// expected-error@-1 {{expected type}}
// expected-error@-2 {{value of type 'Int' has no member 'Protocol'}}

let i: 123? // expected-error {{consecutive statements on a line must be separated by ';'}}
// expected-error@-1 {{expected type}}
// expected-error@-2 {{cannot use optional chaining on non-optional value of type 'Int'}}

let j: 123! // expected-error {{consecutive statements on a line must be separated by ';'}}
// expected-error@-1 {{expected type}}
// expected-error@-2 {{cannot force unwrap value of non-optional type 'Int'}}
13 changes: 8 additions & 5 deletions test/Sema/value_generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,21 @@ struct Generic<T: ~Copyable & ~Escapable> {}
struct GenericWithIntParam<T: ~Copyable & ~Escapable, let N: Int> {}

extension Generic where T == 123 {} // expected-error {{cannot constrain type parameter 'T' to be integer '123'}}
extension Generic where T == 123.Type {} // expected-error {{integer unexpectedly used in a type position}}
extension Generic where T == 123.Type {} // expected-error {{cannot constrain type parameter 'T' to be integer '123'}}
// expected-error@-1 {{expected '{' in extension}}
extension Generic where T == 123? {} // expected-error {{cannot constrain type parameter 'T' to be integer '123'}}
// expected-error@-1 {{expected '{' in extension}}

func f(_: Generic<123>) {} // expected-error {{integer unexpectedly used in a type position}}
func g<let N: Int>(_: Generic<N>) {} // expected-error {{cannot use value type 'N' for generic argument 'T'}}
func h(_: (Int, 123)) {} // expected-error {{integer unexpectedly used in a type position}}
func i(_: () -> 123) {} // expected-error {{integer unexpectedly used in a type position}}
func h(_: (Int, 123)) {} // expected-error {{expected type}}
func i(_: () -> 123) {} // expected-error {{expected type}}
func j(_: (A<123>) -> ()) {} // OK
func k(_: some 123) {} // expected-error {{integer unexpectedly used in a type position}}
func k(_: some 123) {} // expected-error {{expected parameter type following ':'}}
func l(_: GenericWithIntParam<123, Int>) {} // expected-error {{cannot pass type 'Int' as a value for generic value 'N'}}
func m(_: GenericWithIntParam<Int, 123>) {} // OK

typealias One = 1 // expected-error {{integer unexpectedly used in a type position}}
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'}}

Expand Down
2 changes: 1 addition & 1 deletion test/attr/attr_implements_bad_parse.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %target-swift-frontend -parse -verify %s

struct S0 {
@_implements(1, Foo) // OK. We can parse integers as types now, so this is fine. We will diagnose its incorrect usage during type checking.
@_implements(1, Foo) // expected-error {{expected type}}
func f() { }
}

Expand Down
4 changes: 2 additions & 2 deletions test/expr/postfix/init/unqualified.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Theodosia: Aaron {

// FIXME: We could optimistically parse this as an expression instead
// expected-error@+2 {{initializers may only be declared within a type}}
// expected-error@+1 {{integer unexpectedly used in a type position}}
// expected-error@+1 {{expected parameter type following ':'}}
init(z: 0)
}

Expand Down Expand Up @@ -98,7 +98,7 @@ struct AaronStruct {

// FIXME: We could optimistically parse this as an expression instead
// expected-error@+2 {{initializers may only be declared within a type}}
// expected-error@+1 {{integer unexpectedly used in a type position}}
// expected-error@+1 {{expected parameter type following ':'}}
init(y: 1)
}

Expand Down