Skip to content

Commit 768b987

Browse files
committed
[SwiftParser] Avoid consuming invalid dependsOn and nonisolated modifiers while skipping
Otherwise in situations like `nonisolated()` `canParseType` would return `true` because `()` is valid type.
1 parent b8b4593 commit 768b987

File tree

1 file changed

+58
-7
lines changed

1 file changed

+58
-7
lines changed

Sources/SwiftParser/Types.swift

+58-7
Original file line numberDiff line numberDiff line change
@@ -687,27 +687,74 @@ extension Parser.Lookahead {
687687
return true
688688
}
689689

690-
mutating func skipTypeAttributeList() {
690+
mutating func canParseTypeAttributeList() -> Bool {
691691
var specifierProgress = LoopProgressCondition()
692692
while canHaveParameterSpecifier,
693693
self.at(anyIn: SimpleTypeSpecifierSyntax.SpecifierOptions.self) != nil
694694
|| self.at(.keyword(.nonisolated), .keyword(.dependsOn)),
695695
self.hasProgressed(&specifierProgress)
696696
{
697697
switch self.currentToken {
698-
case .keyword(.nonisolated), .keyword(.dependsOn):
698+
case .keyword(.nonisolated):
699+
let canParseNonisolated = self.withLookahead({
700+
// Consume 'nonisolated'
701+
$0.consumeAnyToken()
702+
703+
// The argument is missing but it still could be a valid modifier,
704+
// i.e. `nonisolated` in an inheritance clause.
705+
guard $0.at(TokenSpec(.leftParen, allowAtStartOfLine: false)) else {
706+
return true
707+
}
708+
709+
// Consume '('
710+
$0.consumeAnyToken()
711+
712+
// nonisolated accepts a single modifier at the moment: 'nonsending'
713+
// we need to check for that explicitly to avoid misinterpreting this
714+
// keyword to be a modifier when it isn't i.e. `[nonisolated(42)]`
715+
guard $0.consume(if: TokenSpec(.nonsending, allowAtStartOfLine: false)) != nil else {
716+
return false
717+
}
718+
719+
return $0.consume(if: TokenSpec(.rightParen, allowAtStartOfLine: false)) != nil
720+
})
721+
722+
guard canParseNonisolated else {
723+
return false
724+
}
725+
699726
self.consumeAnyToken()
700727

701-
// The argument is missing but it still could be a valid modifier,
702-
// i.e. `nonisolated` in an inheritance clause.
703728
guard self.at(TokenSpec(.leftParen, allowAtStartOfLine: false)) else {
704729
continue
705730
}
706731

707-
if self.withLookahead({ $0.atAttributeOrSpecifierArgument() }) {
708-
skipSingle()
732+
self.skipSingle()
733+
734+
case .keyword(.dependsOn):
735+
let canParseDependsOn = self.withLookahead({
736+
// Consume 'dependsOn'
737+
$0.consumeAnyToken()
738+
739+
if $0.currentToken.isAtStartOfLine {
740+
return false
741+
}
742+
743+
// `dependsOn` requires an argument list.
744+
guard $0.atAttributeOrSpecifierArgument() else {
745+
return false
746+
}
747+
748+
return true
749+
})
750+
751+
guard canParseDependsOn else {
752+
return false
709753
}
710754

755+
self.consumeAnyToken()
756+
self.skipSingle()
757+
711758
default:
712759
self.consumeAnyToken()
713760
}
@@ -718,10 +765,14 @@ extension Parser.Lookahead {
718765
self.consumeAnyToken()
719766
self.skipTypeAttribute()
720767
}
768+
769+
return true
721770
}
722771

723772
mutating func canParseTypeScalar() -> Bool {
724-
self.skipTypeAttributeList()
773+
guard self.canParseTypeAttributeList() else {
774+
return false
775+
}
725776

726777
guard self.canParseSimpleOrCompositionType() else {
727778
return false

0 commit comments

Comments
 (0)