Skip to content

[ASTGen/Parse] Implement ASTGen changes for integer generics from Swift Syntax and restrict parsing integer types in certain contexts #77149

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

Merged
merged 10 commits into from
Nov 7, 2024
6 changes: 6 additions & 0 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -1938,6 +1938,12 @@ BridgedVarargTypeRepr_createParsed(BridgedASTContext cContext,
BridgedTypeRepr base,
BridgedSourceLoc cEllipsisLoc);

SWIFT_NAME(
"BridgedIntegerTypeRepr.createParsed(_:string:loc:minusLoc:)")
BridgedIntegerTypeRepr BridgedIntegerTypeRepr_createParsed(
BridgedASTContext cContext, BridgedStringRef cString, BridgedSourceLoc cLoc,
BridgedSourceLoc cMinusLoc);

SWIFT_NAME("BridgedTypeRepr.dump(self:)")
void BridgedTypeRepr_dump(BridgedTypeRepr type);

Expand Down
5 changes: 5 additions & 0 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,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
10 changes: 10 additions & 0 deletions lib/AST/Bridging/TypeReprBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,13 @@ BridgedExistentialTypeRepr_createParsed(BridgedASTContext cContext,
return new (context)
ExistentialTypeRepr(cAnyLoc.unbridged(), baseTy.unbridged());
}

BridgedIntegerTypeRepr
BridgedIntegerTypeRepr_createParsed(BridgedASTContext cContext,
BridgedStringRef cString,
BridgedSourceLoc cLoc,
BridgedSourceLoc cMinusLoc) {
ASTContext &context = cContext.unbridged();
return new (context) IntegerTypeRepr(cString.unbridged(), cLoc.unbridged(),
cMinusLoc.unbridged());
}
4 changes: 2 additions & 2 deletions lib/ASTGen/Sources/ASTGen/Exprs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ extension ASTGenVisitor {
if let generics = node.genericArgumentClause {
leftAngleLoc = self.generateSourceLoc(generics.leftAngle)
genericArgs = generics.arguments.map {
self.generate(type: $0.argument)
self.generate(genericArgument: $0.argument)
}
rightAngleLoc = self.generateSourceLoc(generics.rightAngle)
} else {
Expand Down Expand Up @@ -760,7 +760,7 @@ extension ASTGenVisitor {
let generics = node.genericArgumentClause
let lAngleLoc = self.generateSourceLoc(generics.leftAngle)
let genericArguments = generics.arguments.lazy.map {
self.generate(type: $0.argument)
self.generate(genericArgument: $0.argument)
}
let rAngleLoc = self.generateSourceLoc(generics.rightAngle)
return .createParsed(
Expand Down
74 changes: 72 additions & 2 deletions lib/ASTGen/Sources/ASTGen/Generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
//===----------------------------------------------------------------------===//

import ASTBridging

@_spi(ExperimentalLanguageFeatures)
@_spi(RawSyntax)
import SwiftSyntax

extension ASTGenVisitor {
Expand Down Expand Up @@ -72,8 +75,8 @@ extension ASTGenVisitor {
return BridgedRequirementRepr(
SeparatorLoc: self.generateSourceLoc(sameType.equal),
Kind: .sameType,
FirstType: self.generate(type: sameType.leftType),
SecondType: self.generate(type: sameType.rightType)
FirstType: self.generate(sameTypeLeftType: sameType.leftType),
SecondType: self.generate(sameTypeRightType: sameType.rightType)
)
case .layoutRequirement(_):
// FIXME: Implement layout requirement translation.
Expand All @@ -87,4 +90,71 @@ extension ASTGenVisitor {
requirements: requirements.bridgedArray(in: self)
)
}

func generate(sameTypeLeftType node: SameTypeRequirementSyntax.LeftType) -> BridgedTypeRepr {
switch node {
case .type(let type):
return self.generate(type: type)

case .expr(let expr):
return self.generateIntegerType(expr: expr).asTypeRepr
}
}

func generate(sameTypeRightType node: SameTypeRequirementSyntax.RightType) -> BridgedTypeRepr {
switch node {
case .type(let type):
return self.generate(type: type)

case .expr(let expr):
return self.generateIntegerType(expr: expr).asTypeRepr
}
}

func generate(genericArgument node: GenericArgumentSyntax.Argument) -> BridgedTypeRepr {
switch node {
case .type(let type):
return self.generate(type: type)

case .expr(let expr):
return self.generateIntegerType(expr: expr).asTypeRepr
}
}

func generateIntegerType(expr node: ExprSyntax) -> BridgedIntegerTypeRepr {
var minusLoc = BridgedSourceLoc()
let literalExpr: IntegerLiteralExprSyntax

// The only expressions generic argument types support right now are
// integer literals, '123', and prefix operators for negative integer
// literals, '-123'.
switch node.as(ExprSyntaxEnum.self) {
case .integerLiteralExpr(let node):
literalExpr = node

case .prefixOperatorExpr(let node):
let op = node.operator

guard op.text == "-" else {
fatalError("Unknown prefix operator for generic argument type")
}

guard let node = node.expression.as(IntegerLiteralExprSyntax.self) else {
fatalError("Unknown expression kind for generic argument type")
}

minusLoc = self.generateSourceLoc(op)
literalExpr = node

default:
fatalError("Unknown expression kind for generic argument type")
}

return .createParsed(
self.ctx,
string: self.copyAndStripUnderscores(text: literalExpr.literal.rawText),
loc: self.generateSourceLoc(literalExpr),
minusLoc: minusLoc
)
}
}
1 change: 1 addition & 0 deletions lib/ASTGen/Sources/ASTGen/SourceFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ extension Parser.ExperimentalFeatures {
mapFeature(.NonescapableTypes, to: .nonescapableTypes)
mapFeature(.TrailingComma, to: .trailingComma)
mapFeature(.CoroutineAccessors, to: .coroutineAccessors)
mapFeature(.ValueGenerics, to: .valueGenerics)
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/ASTGen/Sources/ASTGen/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ extension ASTGenVisitor {
}

let genericArguments = generics.arguments.lazy.map {
self.generate(type: $0.argument)
self.generate(genericArgument: $0.argument)
}

return BridgedUnqualifiedIdentTypeRepr.createParsed(
Expand All @@ -140,7 +140,7 @@ extension ASTGenVisitor {
let angleRange: BridgedSourceRange
if let generics = node.genericArgumentClause {
genericArguments = generics.arguments.lazy.map {
self.generate(type: $0.argument)
self.generate(genericArgument: $0.argument)
}.bridgedArray(in: self)

angleRange = self.generateSourceRange(start: generics.leftAngle, end: generics.rightAngle)
Expand Down
25 changes: 21 additions & 4 deletions lib/Macros/Sources/SwiftMacros/DistributedResolvableMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//
//===----------------------------------------------------------------------===//

@_spi(ExperimentalLanguageFeatures)
import SwiftSyntax
import SwiftSyntaxMacros
import SwiftDiagnostics
Expand Down Expand Up @@ -141,10 +142,25 @@ extension DistributedResolvableMacro {
specificActorSystemRequirement = conformanceReq.rightType.trimmed
isGenericStub = true

case .sameTypeRequirement(let sameTypeReq)
where sameTypeReq.leftType.isActorSystem:
specificActorSystemRequirement = sameTypeReq.rightType.trimmed
isGenericStub = false
case .sameTypeRequirement(let sameTypeReq):
switch sameTypeReq.leftType {
case .type(let type) where type.isActorSystem:
switch sameTypeReq.rightType.trimmed {
case .type(let rightType):
specificActorSystemRequirement = rightType
isGenericStub = false

case .expr:
throw DiagnosticsError(
syntax: sameTypeReq.rightType,
message: "Expression type not supported for distributed actor",
id: .invalidGenericArgument
)
}

default:
continue
}

default:
continue
Expand Down Expand Up @@ -265,6 +281,7 @@ struct DistributedResolvableMacroDiagnostic: DiagnosticMessage {
enum ID: String {
case invalidApplication = "invalid type"
case missingInitializer = "missing initializer"
case invalidGenericArgument = "invalid generic argument"
}

var message: String
Expand Down
2 changes: 1 addition & 1 deletion lib/Macros/Sources/SwiftMacros/OptionSetMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public struct OptionSetMacro {
of attribute: AttributeSyntax,
attachedTo decl: Decl,
in context: Context
) -> (StructDeclSyntax, EnumDeclSyntax, TypeSyntax)? {
) -> (StructDeclSyntax, EnumDeclSyntax, GenericArgumentSyntax.Argument)? {
// Determine the name of the options enum.
let optionsEnumName: String
if case let .argumentList(arguments) = attribute.arguments,
Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3963,7 +3963,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 @@ -1067,6 +1067,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 @@ -3122,7 +3158,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
Loading