Skip to content

Commit 6c7b916

Browse files
committed
wip
1 parent fb65fcb commit 6c7b916

File tree

2 files changed

+272
-0
lines changed

2 files changed

+272
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
//
2+
// ArgumentMatcher.swift
3+
// swift-syntax
4+
//
5+
// Created by Kim de Vos on 13/04/2025.
6+
//
7+
8+
9+
public struct CallArgumentMatcher {
10+
public static func matchCallArgumentsImpl(
11+
args: inout [FunctionParameterSyntax],
12+
params: [FunctionParameterSyntax],
13+
paramInfo: ParameterListInfo,
14+
unlabeledTrailingClosureArgIndex: Int?,
15+
allowFixes: Bool,
16+
trailingClosureMatching: TrailingClosureMatching,
17+
listener: MatchCallArgumentListener,
18+
parameterBindings: inout [ParamBinding]
19+
) {
20+
// assert(params.size() == paramInfo.size() && "Default map does not match");
21+
// assert(!unlabeledTrailingClosureArgIndex ||
22+
// *unlabeledTrailingClosureArgIndex < args.size());
23+
//
24+
// // Keep track of the parameter we're matching and what argument indices
25+
// // got bound to each parameter.
26+
// unsigned numParams = params.size();
27+
// parameterBindings.clear();
28+
// parameterBindings.resize(numParams);
29+
//
30+
// // Keep track of which arguments we have claimed from the argument tuple.
31+
// unsigned numArgs = args.size();
32+
// SmallVector<bool, 4> claimedArgs(numArgs, false);
33+
// SmallVector<Identifier, 4> actualArgNames;
34+
// unsigned numClaimedArgs = 0;
35+
//
36+
// // Indicates whether any of the arguments are potentially out-of-order,
37+
// // requiring further checking at the end.
38+
// bool potentiallyOutOfOrder = false;
39+
//
40+
// // Local function that claims the argument at \c argIdx, returning the
41+
// // index of the claimed argument. This is primarily a helper for
42+
// // \c claimNextNamed.
43+
// auto claim = [&](Identifier expectedName, unsigned argIdx,
44+
// bool ignoreNameClash = false) -> unsigned {
45+
// // Make sure we can claim this argument.
46+
// assert(argIdx != numArgs && "Must have a valid index to claim");
47+
// assert(!claimedArgs[argIdx] && "Argument already claimed");
48+
//
49+
// if (!actualArgNames.empty()) {
50+
// // We're recording argument names; record this one.
51+
// actualArgNames[argIdx] = expectedName;
52+
// } else if (!ignoreNameClash && !args[argIdx].matchParameterLabel(expectedName)) {
53+
// // We have an argument name mismatch. Start recording argument names.
54+
// actualArgNames.resize(numArgs);
55+
//
56+
// // Figure out previous argument names from the parameter bindings.
57+
// for (auto i : indices(params)) {
58+
// const auto &param = params[i];
59+
// bool firstArg = true;
60+
//
61+
// for (auto argIdx : parameterBindings[i]) {
62+
// actualArgNames[argIdx] = firstArg ? param.getLabel() : Identifier();
63+
// firstArg = false;
64+
// }
65+
// }
66+
//
67+
// // Record this argument name.
68+
// actualArgNames[argIdx] = expectedName;
69+
// }
70+
//
71+
// claimedArgs[argIdx] = true;
72+
// ++numClaimedArgs;
73+
// return argIdx;
74+
// };
75+
//
76+
// // Local function that skips over any claimed arguments.
77+
// auto skipClaimedArgs = [&](unsigned &nextArgIdx) {
78+
// while (nextArgIdx != numArgs && claimedArgs[nextArgIdx])
79+
// ++nextArgIdx;
80+
// return nextArgIdx;
81+
// };
82+
//
83+
// // Local function that retrieves the next unclaimed argument with the given
84+
// // name (which may be empty). This routine claims the argument.
85+
// auto claimNextNamed =
86+
// [&](unsigned &nextArgIdx, Identifier paramLabel, bool ignoreNameMismatch,
87+
// bool forVariadic = false) -> std::optional<unsigned> {
88+
// // Skip over any claimed arguments.
89+
// skipClaimedArgs(nextArgIdx);
90+
//
91+
// // If we've claimed all of the arguments, there's nothing more to do.
92+
// if (numClaimedArgs == numArgs)
93+
// return std::nullopt;
94+
//
95+
// // Go hunting for an unclaimed argument whose name does match.
96+
// std::optional<unsigned> claimedWithSameName;
97+
// unsigned firstArgIdx = nextArgIdx;
98+
// for (unsigned i = nextArgIdx; i != numArgs; ++i) {
99+
// auto argLabel = args[i].getLabel();
100+
// bool claimIgnoringNameMismatch = false;
101+
//
102+
// if (!args[i].matchParameterLabel(paramLabel)) {
103+
// // If this is an attempt to claim additional unlabeled arguments
104+
// // for variadic parameter, we have to stop at first labeled argument.
105+
// if (forVariadic)
106+
// return std::nullopt;
107+
//
108+
// if ((i == firstArgIdx || ignoreNameMismatch) &&
109+
// listener.canClaimArgIgnoringNameMismatch(args[i])) {
110+
// // Avoid triggering relabelling fixes about the completion arg.
111+
// claimIgnoringNameMismatch = true;
112+
// } else {
113+
// // Otherwise we can continue trying to find argument which
114+
// // matches parameter with or without label.
115+
// continue;
116+
// }
117+
// }
118+
//
119+
// // Skip claimed arguments.
120+
// if (claimedArgs[i]) {
121+
// assert(!forVariadic && "Cannot be for a variadic claim");
122+
// // Note that we have already claimed an argument with the same name.
123+
// if (!claimedWithSameName)
124+
// claimedWithSameName = i;
125+
// continue;
126+
// }
127+
//
128+
// // We found a match. If the match wasn't the next one, we have
129+
// // potentially out of order arguments.
130+
// if (i != nextArgIdx) {
131+
// assert(!forVariadic && "Cannot be for a variadic claim");
132+
// // Avoid claiming un-labeled defaulted parameters
133+
// // by out-of-order un-labeled arguments or parts
134+
// // of variadic argument sequence, because that might
135+
// // be incorrect:
136+
// // ```swift
137+
// // func foo(_ a: Int, _ b: Int = 0, c: Int = 0, _ d: Int) {}
138+
// // foo(1, c: 2, 3) // -> `3` will be claimed as '_ b:'.
139+
// // ```
140+
// if (argLabel.empty() && !claimIgnoringNameMismatch)
141+
// continue;
142+
//
143+
// potentiallyOutOfOrder = true;
144+
// }
145+
//
146+
// // Claim it.
147+
// return claim(paramLabel, i, claimIgnoringNameMismatch);
148+
// }
149+
//
150+
// // If we're not supposed to attempt any fixes, we're done.
151+
// if (!allowFixes)
152+
// return std::nullopt;
153+
//
154+
// // Several things could have gone wrong here, and we'll check for each
155+
// // of them at some point:
156+
// // - The keyword argument might be redundant, in which case we can point
157+
// // out the issue.
158+
// // - The argument might be unnamed, in which case we try to fix the
159+
// // problem by adding the name.
160+
// // - The argument might have extraneous label, in which case we try to
161+
// // fix the problem by removing such label.
162+
// // - The keyword argument might be a typo for an actual argument name, in
163+
// // which case we should find the closest match to correct to.
164+
//
165+
// // Missing or extraneous label.
166+
// if (nextArgIdx != numArgs && ignoreNameMismatch) {
167+
// auto argLabel = args[nextArgIdx].getLabel();
168+
// // Claim this argument if we are asked to ignore labeling failure,
169+
// // only if argument doesn't have a label when parameter expected
170+
// // it to, or vice versa.
171+
// if (paramLabel.empty() || argLabel.empty())
172+
// return claim(paramLabel, nextArgIdx);
173+
// }
174+
//
175+
// // Redundant keyword arguments.
176+
// if (claimedWithSameName) {
177+
// // FIXME: We can provide better diagnostics here.
178+
// return std::nullopt;
179+
// }
180+
//
181+
// // Typo correction is handled in a later pass.
182+
// return std::nullopt;
183+
}
184+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//
2+
// ParameterListInfo.swift
3+
// swift-syntax
4+
//
5+
// Created by Kim de Vos on 13/04/2025.
6+
//
7+
8+
/// Provides information about the parameter list of a given declaration, including whether each parameter
9+
/// has a default argument.
10+
struct ParameterListInfo {
11+
private var defaultArguments: [Bool]
12+
private var acceptsUnlabeledTrailingClosures: [Bool]
13+
private var propertyWrappers: [Bool]
14+
private var implicitSelfCapture: [Bool]
15+
private var inheritActorContext: [Bool]
16+
private var variadicGenerics: [Bool]
17+
private var sendingParameters: [Bool]
18+
19+
/// Default initializer
20+
init() {
21+
self.defaultArguments = []
22+
self.acceptsUnlabeledTrailingClosures = []
23+
self.propertyWrappers = []
24+
self.implicitSelfCapture = []
25+
self.inheritActorContext = []
26+
self.variadicGenerics = []
27+
self.sendingParameters = []
28+
}
29+
30+
/// Custom initializer with parameters
31+
init(params: [FunctionParameterSyntax], paramOwner: DeclSyntax?, skipCurriedSelf: Bool) {
32+
self.defaultArguments = Array(repeating: false, count: params.count)
33+
self.acceptsUnlabeledTrailingClosures = Array(repeating: false, count: params.count)
34+
self.propertyWrappers = Array(repeating: false, count: params.count)
35+
self.implicitSelfCapture = Array(repeating: false, count: params.count)
36+
self.inheritActorContext = Array(repeating: false, count: params.count)
37+
self.variadicGenerics = Array(repeating: false, count: params.count)
38+
self.sendingParameters = Array(repeating: false, count: params.count)
39+
}
40+
41+
/// Whether the parameter at the given index has a default argument.
42+
func hasDefaultArgument(paramIdx: Int) -> Bool {
43+
return defaultArguments[paramIdx]
44+
}
45+
46+
/// Whether the parameter accepts an unlabeled trailing closure argument
47+
/// according to the "forward-scan" rule.
48+
func acceptsUnlabeledTrailingClosureArgument(paramIdx: Int) -> Bool {
49+
return acceptsUnlabeledTrailingClosures[paramIdx]
50+
}
51+
52+
/// The ParamDecl at the given index if the parameter has an applied property wrapper.
53+
func hasExternalPropertyWrapper(paramIdx: Int) -> Bool {
54+
return propertyWrappers[paramIdx]
55+
}
56+
57+
/// Whether the given parameter is a closure that should allow capture of
58+
/// 'self' to be implicit, without requiring "self.".
59+
func isImplicitSelfCapture(paramIdx: Int) -> Bool {
60+
return implicitSelfCapture[paramIdx]
61+
}
62+
63+
/// Whether the given parameter is a closure that should inherit the actor context
64+
/// from the context in which it was created.
65+
func inheritsActorContext(paramIdx: Int) -> Bool {
66+
return inheritActorContext[paramIdx]
67+
}
68+
69+
/// Whether the parameter is a variadic generic parameter.
70+
func isVariadicGenericParameter(paramIdx: Int) -> Bool {
71+
return variadicGenerics[paramIdx]
72+
}
73+
74+
/// Returns true if this is a sending parameter.
75+
func isSendingParameter(paramIdx: Int) -> Bool {
76+
return sendingParameters[paramIdx]
77+
}
78+
79+
/// Retrieve the number of non-defaulted parameters.
80+
func numNonDefaultedParameters() -> Int {
81+
return defaultArguments.filter { !$0 }.count
82+
}
83+
84+
/// Retrieve the number of parameters for which we have information.
85+
func size() -> Int {
86+
return defaultArguments.count
87+
}
88+
}

0 commit comments

Comments
 (0)