@effect/language-service 0.55.2 → 0.55.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +183 -21
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +178 -12
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +267 -37
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +183 -21
- package/transform.js.map +1 -1
package/cli.js
CHANGED
|
@@ -30069,8 +30069,9 @@ var contAll = Symbol.for("Nano.contAll");
|
|
|
30069
30069
|
var NanoYield = Symbol.for("Nano.yield");
|
|
30070
30070
|
var args2 = Symbol.for("Nano.args");
|
|
30071
30071
|
var NanoDefectException = class {
|
|
30072
|
-
constructor(message) {
|
|
30072
|
+
constructor(message, lastSpan) {
|
|
30073
30073
|
this.message = message;
|
|
30074
|
+
this.lastSpan = lastSpan;
|
|
30074
30075
|
}
|
|
30075
30076
|
_tag = "@effect/language-service/NanoDefectException";
|
|
30076
30077
|
};
|
|
@@ -30128,6 +30129,7 @@ var NanoFiber = class {
|
|
|
30128
30129
|
_services = {};
|
|
30129
30130
|
_cache = {};
|
|
30130
30131
|
_perf = false;
|
|
30132
|
+
_lastSpan = "";
|
|
30131
30133
|
runLoop(nano) {
|
|
30132
30134
|
let current = nano;
|
|
30133
30135
|
while (true) {
|
|
@@ -30158,17 +30160,21 @@ var WithSpanProto = {
|
|
|
30158
30160
|
[evaluate2](fiber) {
|
|
30159
30161
|
const [fa, name] = this[args2];
|
|
30160
30162
|
if (!fiber._perf) return fa;
|
|
30163
|
+
const previousSpan = fiber._lastSpan;
|
|
30164
|
+
fiber._lastSpan = name;
|
|
30161
30165
|
const start4 = performance.now();
|
|
30162
30166
|
timingsCount[name] = (timingsCount[name] || 0) + 1;
|
|
30163
30167
|
return match17(fa, {
|
|
30164
30168
|
onSuccess: (_) => {
|
|
30165
30169
|
const end5 = performance.now();
|
|
30166
30170
|
timings[name] = (timings[name] || 0) + (end5 - start4);
|
|
30171
|
+
fiber._lastSpan = previousSpan;
|
|
30167
30172
|
return succeed17(_);
|
|
30168
30173
|
},
|
|
30169
30174
|
onFailure: (_) => {
|
|
30170
30175
|
const end5 = performance.now();
|
|
30171
30176
|
timings[name] = (timings[name] || 0) + (end5 - start4);
|
|
30177
|
+
fiber._lastSpan = previousSpan;
|
|
30172
30178
|
return fail18(_);
|
|
30173
30179
|
}
|
|
30174
30180
|
});
|
|
@@ -30179,19 +30185,16 @@ var withSpan6 = (name) => (fa) => {
|
|
|
30179
30185
|
nano[args2] = [fa, name];
|
|
30180
30186
|
return nano;
|
|
30181
30187
|
};
|
|
30182
|
-
var unsafeRun = (nano) => {
|
|
30183
|
-
const fiber = new NanoFiber();
|
|
30184
|
-
const result = fiber.runLoop(nano);
|
|
30185
|
-
if (result._tag === "Success") {
|
|
30186
|
-
return right2(result.value);
|
|
30187
|
-
}
|
|
30188
|
-
return left2(result.value);
|
|
30189
|
-
};
|
|
30190
30188
|
var run9 = (nano) => {
|
|
30189
|
+
const fiber = new NanoFiber();
|
|
30191
30190
|
try {
|
|
30192
|
-
|
|
30191
|
+
const result = fiber.runLoop(nano);
|
|
30192
|
+
if (result._tag === "Success") {
|
|
30193
|
+
return right2(result.value);
|
|
30194
|
+
}
|
|
30195
|
+
return left2(result.value);
|
|
30193
30196
|
} catch (e) {
|
|
30194
|
-
return left2(new NanoDefectException(e));
|
|
30197
|
+
return left2(new NanoDefectException(e, fiber._lastSpan));
|
|
30195
30198
|
}
|
|
30196
30199
|
};
|
|
30197
30200
|
var OnSuccessProto2 = {
|
|
@@ -30298,7 +30301,7 @@ var ServiceProto = {
|
|
|
30298
30301
|
return cont2 ? cont2[contA](value5, fiber) : fiber.yieldWith(succeed17(value5));
|
|
30299
30302
|
}
|
|
30300
30303
|
const cont = fiber.getCont(contE);
|
|
30301
|
-
return cont ? cont[contE](tag4, fiber) : fiber.yieldWith(fail18(new NanoDefectException(`Service ${tag4.key} not found
|
|
30304
|
+
return cont ? cont[contE](tag4, fiber) : fiber.yieldWith(fail18(new NanoDefectException(`Service ${tag4.key} not found`, fiber._lastSpan)));
|
|
30302
30305
|
}
|
|
30303
30306
|
};
|
|
30304
30307
|
var service2 = (tag4) => {
|
|
@@ -30877,6 +30880,30 @@ function makeTypeScriptUtils(ts) {
|
|
|
30877
30880
|
}
|
|
30878
30881
|
return node;
|
|
30879
30882
|
}
|
|
30883
|
+
function isOuterExpression(node, kinds = ts.OuterExpressionKinds.All) {
|
|
30884
|
+
switch (node.kind) {
|
|
30885
|
+
case ts.SyntaxKind.ParenthesizedExpression:
|
|
30886
|
+
return (kinds & ts.OuterExpressionKinds.Parentheses) !== 0;
|
|
30887
|
+
case ts.SyntaxKind.TypeAssertionExpression:
|
|
30888
|
+
case ts.SyntaxKind.AsExpression:
|
|
30889
|
+
return (kinds & ts.OuterExpressionKinds.TypeAssertions) !== 0;
|
|
30890
|
+
case ts.SyntaxKind.SatisfiesExpression:
|
|
30891
|
+
return (kinds & (ts.OuterExpressionKinds.TypeAssertions | ts.OuterExpressionKinds.Satisfies)) !== 0;
|
|
30892
|
+
case ts.SyntaxKind.ExpressionWithTypeArguments:
|
|
30893
|
+
return (kinds & ts.OuterExpressionKinds.ExpressionsWithTypeArguments) !== 0;
|
|
30894
|
+
case ts.SyntaxKind.NonNullExpression:
|
|
30895
|
+
return (kinds & ts.OuterExpressionKinds.NonNullAssertions) !== 0;
|
|
30896
|
+
case ts.SyntaxKind.PartiallyEmittedExpression:
|
|
30897
|
+
return (kinds & ts.OuterExpressionKinds.PartiallyEmittedExpressions) !== 0;
|
|
30898
|
+
}
|
|
30899
|
+
return false;
|
|
30900
|
+
}
|
|
30901
|
+
function skipOuterExpressions(node, kinds = ts.OuterExpressionKinds.All) {
|
|
30902
|
+
while (isOuterExpression(node, kinds)) {
|
|
30903
|
+
node = node.expression;
|
|
30904
|
+
}
|
|
30905
|
+
return node;
|
|
30906
|
+
}
|
|
30880
30907
|
return {
|
|
30881
30908
|
findNodeAtPositionIncludingTrivia,
|
|
30882
30909
|
parsePackageContentNameAndVersionFromScope,
|
|
@@ -30897,7 +30924,9 @@ function makeTypeScriptUtils(ts) {
|
|
|
30897
30924
|
createEffectGenCallExpressionWithBlock,
|
|
30898
30925
|
createReturnYieldStarStatement,
|
|
30899
30926
|
parseAccessedExpressionForCompletion,
|
|
30900
|
-
getSourceFileOfNode
|
|
30927
|
+
getSourceFileOfNode,
|
|
30928
|
+
isOuterExpression,
|
|
30929
|
+
skipOuterExpressions
|
|
30901
30930
|
};
|
|
30902
30931
|
}
|
|
30903
30932
|
|
|
@@ -31330,6 +31359,14 @@ var createDiagnosticExecutor = fn2("LSP.createCommentDirectivesProcessor")(
|
|
|
31330
31359
|
result = node2;
|
|
31331
31360
|
return;
|
|
31332
31361
|
}
|
|
31362
|
+
if (ts.isPropertyAssignment(node2)) {
|
|
31363
|
+
const realStart = ts.getTokenPosOfNode(node2, sourceFile);
|
|
31364
|
+
const starts = sourceFile.getLineStarts().filter((start4) => start4 >= node2.pos && start4 <= realStart);
|
|
31365
|
+
if (starts.length > 0) {
|
|
31366
|
+
result = node2;
|
|
31367
|
+
return;
|
|
31368
|
+
}
|
|
31369
|
+
}
|
|
31333
31370
|
if (result) return;
|
|
31334
31371
|
if (node2.parent) find3(node2.parent);
|
|
31335
31372
|
}
|
|
@@ -31941,6 +31978,7 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
31941
31978
|
const getSourceFilesDeclaringSymbolModule = (packageName) => cachedBy(
|
|
31942
31979
|
fn2("TypeParser.getSourceFilesDeclaringSymbolModule")(function* (symbol3) {
|
|
31943
31980
|
const result = [];
|
|
31981
|
+
if (!symbol3) return result;
|
|
31944
31982
|
if (!symbol3.declarations) return yield* typeParserIssue("Symbol has no declarations", void 0, void 0);
|
|
31945
31983
|
for (const sourceFile of symbol3.declarations) {
|
|
31946
31984
|
if (!ts.isSourceFile(sourceFile)) continue;
|
|
@@ -31978,6 +32016,7 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
31978
32016
|
const getSourceFilesDeclaringSymbolExportedUnderPackageModule = (packageName, memberName) => cachedBy(
|
|
31979
32017
|
fn2("TypeParser.getSourceFilesDeclaringSymbolUnderPackageExportedMember")(function* (symbol3) {
|
|
31980
32018
|
const result = [];
|
|
32019
|
+
if (!symbol3) return result;
|
|
31981
32020
|
if (!symbol3.declarations) return yield* typeParserIssue("Symbol has no declarations", void 0, void 0);
|
|
31982
32021
|
for (const declaration of symbol3.declarations) {
|
|
31983
32022
|
const sourceFile = tsUtils.getSourceFileOfNode(declaration);
|
|
@@ -32199,14 +32238,14 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
32199
32238
|
);
|
|
32200
32239
|
const importedContextModule = cachedBy(
|
|
32201
32240
|
fn2("TypeParser.importedContextModule")(function* (node) {
|
|
32241
|
+
if (!ts.isIdentifier(node)) {
|
|
32242
|
+
return yield* typeParserIssue("Node is not an identifier", void 0, node);
|
|
32243
|
+
}
|
|
32202
32244
|
const type2 = typeChecker.getTypeAtLocation(node);
|
|
32203
32245
|
const propertySymbol = typeChecker.getPropertyOfType(type2, "Tag");
|
|
32204
32246
|
if (!propertySymbol) {
|
|
32205
32247
|
return yield* typeParserIssue("Type has no 'Tag' property", type2, node);
|
|
32206
32248
|
}
|
|
32207
|
-
if (!ts.isIdentifier(node)) {
|
|
32208
|
-
return yield* typeParserIssue("Node is not an identifier", type2, node);
|
|
32209
|
-
}
|
|
32210
32249
|
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
32211
32250
|
if (!sourceFile) {
|
|
32212
32251
|
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
@@ -32233,14 +32272,14 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
32233
32272
|
);
|
|
32234
32273
|
const importedDataModule = cachedBy(
|
|
32235
32274
|
fn2("TypeParser.importedDataModule")(function* (node) {
|
|
32275
|
+
if (!ts.isIdentifier(node)) {
|
|
32276
|
+
return yield* typeParserIssue("Node is not an expression", void 0, node);
|
|
32277
|
+
}
|
|
32236
32278
|
const type2 = typeChecker.getTypeAtLocation(node);
|
|
32237
32279
|
const propertySymbol = typeChecker.getPropertyOfType(type2, "TaggedError");
|
|
32238
32280
|
if (!propertySymbol) {
|
|
32239
32281
|
return yield* typeParserIssue("Type has no 'TaggedError' property", type2, node);
|
|
32240
32282
|
}
|
|
32241
|
-
if (!ts.isIdentifier(node)) {
|
|
32242
|
-
return yield* typeParserIssue("Node is not an expression", type2, node);
|
|
32243
|
-
}
|
|
32244
32283
|
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
32245
32284
|
if (!sourceFile) {
|
|
32246
32285
|
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
@@ -33024,6 +33063,103 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
33024
33063
|
};
|
|
33025
33064
|
}
|
|
33026
33065
|
|
|
33066
|
+
// src/diagnostics/anyUnknownInErrorContext.ts
|
|
33067
|
+
var anyUnknownInErrorContext = createDiagnostic({
|
|
33068
|
+
name: "anyUnknownInErrorContext",
|
|
33069
|
+
code: 28,
|
|
33070
|
+
severity: "off",
|
|
33071
|
+
apply: fn2("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
33072
|
+
const ts = yield* service2(TypeScriptApi);
|
|
33073
|
+
const typeChecker = yield* service2(TypeCheckerApi);
|
|
33074
|
+
const typeParser = yield* service2(TypeParser);
|
|
33075
|
+
const isAnyOrUnknown = (type2) => (type2.flags & ts.TypeFlags.Any) > 0 || (type2.flags & ts.TypeFlags.Unknown) > 0;
|
|
33076
|
+
const matchingNodes = [];
|
|
33077
|
+
const nodeToVisit = [sourceFile];
|
|
33078
|
+
const appendNodeToVisit = (node) => {
|
|
33079
|
+
nodeToVisit.push(node);
|
|
33080
|
+
return void 0;
|
|
33081
|
+
};
|
|
33082
|
+
while (nodeToVisit.length > 0) {
|
|
33083
|
+
const node = nodeToVisit.pop();
|
|
33084
|
+
if (ts.isTypeNode(node)) continue;
|
|
33085
|
+
if (ts.isTypeAliasDeclaration(node)) continue;
|
|
33086
|
+
if (ts.isInterfaceDeclaration(node)) continue;
|
|
33087
|
+
if (ts.isAsExpression(node) && node.type && node.type.kind === ts.SyntaxKind.AnyKeyword) {
|
|
33088
|
+
continue;
|
|
33089
|
+
}
|
|
33090
|
+
if (ts.isParameter(node) || ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
|
|
33091
|
+
if (node.type) {
|
|
33092
|
+
const type3 = typeChecker.getTypeAtLocation(node.type);
|
|
33093
|
+
const expectedEffect = yield* pipe(
|
|
33094
|
+
typeParser.strictEffectType(type3, node.type),
|
|
33095
|
+
orElse14(() => void_8)
|
|
33096
|
+
);
|
|
33097
|
+
if (expectedEffect) continue;
|
|
33098
|
+
}
|
|
33099
|
+
}
|
|
33100
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
33101
|
+
if (!ts.isExpression(node)) continue;
|
|
33102
|
+
let type2 = typeChecker.getTypeAtLocation(node);
|
|
33103
|
+
if (ts.isCallExpression(node)) {
|
|
33104
|
+
const resolvedSignature = typeChecker.getResolvedSignature(node);
|
|
33105
|
+
if (resolvedSignature) {
|
|
33106
|
+
type2 = typeChecker.getReturnTypeOfSignature(resolvedSignature);
|
|
33107
|
+
}
|
|
33108
|
+
}
|
|
33109
|
+
if (!type2) continue;
|
|
33110
|
+
yield* pipe(
|
|
33111
|
+
typeParser.strictEffectType(type2, node),
|
|
33112
|
+
map34((effect3) => {
|
|
33113
|
+
const { E, R } = effect3;
|
|
33114
|
+
const hasAnyUnknownR = isAnyOrUnknown(R);
|
|
33115
|
+
const hasAnyUnknownE = isAnyOrUnknown(E);
|
|
33116
|
+
if (hasAnyUnknownR || hasAnyUnknownE) {
|
|
33117
|
+
const channels = [];
|
|
33118
|
+
if (hasAnyUnknownR) {
|
|
33119
|
+
const typeName = R.flags & ts.TypeFlags.Any ? "any" : "unknown";
|
|
33120
|
+
channels.push(`${typeName} in the requirements channel`);
|
|
33121
|
+
}
|
|
33122
|
+
if (hasAnyUnknownE) {
|
|
33123
|
+
const typeName = E.flags & ts.TypeFlags.Any ? "any" : "unknown";
|
|
33124
|
+
channels.push(`${typeName} in the error channel`);
|
|
33125
|
+
}
|
|
33126
|
+
const nodeStart = ts.getTokenPosOfNode(node, sourceFile);
|
|
33127
|
+
const nodeEnd = node.end;
|
|
33128
|
+
for (let i = matchingNodes.length - 1; i >= 0; i--) {
|
|
33129
|
+
const existing = matchingNodes[i];
|
|
33130
|
+
const existingStart = ts.getTokenPosOfNode(existing.node, sourceFile);
|
|
33131
|
+
const existingEnd = existing.node.end;
|
|
33132
|
+
if (existingStart <= nodeStart && existingEnd >= nodeEnd) {
|
|
33133
|
+
matchingNodes.splice(i, 1);
|
|
33134
|
+
}
|
|
33135
|
+
}
|
|
33136
|
+
const suggestions = [`This Effect has ${channels.join(" and ")} which is not recommended.`];
|
|
33137
|
+
if (hasAnyUnknownR) {
|
|
33138
|
+
suggestions.push(`Only service identifiers should appear in the requirements channel.`);
|
|
33139
|
+
}
|
|
33140
|
+
if (hasAnyUnknownE) {
|
|
33141
|
+
suggestions.push(
|
|
33142
|
+
`Having an unknown or any error type is not useful. Consider instead using specific error types baked by Data.TaggedError for example.`
|
|
33143
|
+
);
|
|
33144
|
+
}
|
|
33145
|
+
channels.push(`If you plan to later on manually cast the type, you can safely disable this diagnostic.`);
|
|
33146
|
+
const messageText = suggestions.join("\n");
|
|
33147
|
+
matchingNodes.push({ messageText, node, type: type2 });
|
|
33148
|
+
}
|
|
33149
|
+
}),
|
|
33150
|
+
ignore3
|
|
33151
|
+
);
|
|
33152
|
+
}
|
|
33153
|
+
for (const { messageText, node } of matchingNodes) {
|
|
33154
|
+
report({
|
|
33155
|
+
location: node,
|
|
33156
|
+
messageText,
|
|
33157
|
+
fixes: []
|
|
33158
|
+
});
|
|
33159
|
+
}
|
|
33160
|
+
})
|
|
33161
|
+
});
|
|
33162
|
+
|
|
33027
33163
|
// src/diagnostics/catchUnfailableEffect.ts
|
|
33028
33164
|
var catchUnfailableEffect = createDiagnostic({
|
|
33029
33165
|
name: "catchUnfailableEffect",
|
|
@@ -33785,9 +33921,10 @@ var leakingRequirements = createDiagnostic({
|
|
|
33785
33921
|
(type2) => {
|
|
33786
33922
|
let symbol3 = type2.symbol;
|
|
33787
33923
|
if (symbol3 && symbol3.flags & ts.SymbolFlags.Alias) {
|
|
33788
|
-
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
33924
|
+
symbol3 = typeChecker.getAliasedSymbol(symbol3) || symbol3;
|
|
33789
33925
|
}
|
|
33790
|
-
|
|
33926
|
+
if (!symbol3) return false;
|
|
33927
|
+
return !(symbol3?.declarations || []).some((declaration) => {
|
|
33791
33928
|
const declarationSource = tsUtils.getSourceFileOfNode(declaration);
|
|
33792
33929
|
if (!declarationSource) return false;
|
|
33793
33930
|
return declarationSource.text.substring(declaration.pos, declaration.end).toLowerCase().indexOf(
|
|
@@ -34882,6 +35019,26 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
34882
35019
|
const ts = yield* service2(TypeScriptApi);
|
|
34883
35020
|
const typeParser = yield* service2(TypeParser);
|
|
34884
35021
|
const typeChecker = yield* service2(TypeCheckerApi);
|
|
35022
|
+
function isAllowedConstructor(node) {
|
|
35023
|
+
if (node.body && node.body.statements.length === 1) {
|
|
35024
|
+
const expressionStatement = node.body.statements[0];
|
|
35025
|
+
if (ts.isExpressionStatement(expressionStatement)) {
|
|
35026
|
+
const maybeCallSuper = expressionStatement.expression;
|
|
35027
|
+
if (ts.isCallExpression(maybeCallSuper)) {
|
|
35028
|
+
if (maybeCallSuper.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
35029
|
+
const expectedNames = node.parameters.map((_) => _.name).filter(ts.isIdentifier).map((_) => ts.idText(_));
|
|
35030
|
+
if (expectedNames.length === 2 && expectedNames.length === node.parameters.length) {
|
|
35031
|
+
const givenNames = maybeCallSuper.arguments.filter(ts.isIdentifier).map((_) => ts.idText(_));
|
|
35032
|
+
if (givenNames.length === expectedNames.length && givenNames.every((name, index) => name === expectedNames[index])) {
|
|
35033
|
+
return true;
|
|
35034
|
+
}
|
|
35035
|
+
}
|
|
35036
|
+
}
|
|
35037
|
+
}
|
|
35038
|
+
}
|
|
35039
|
+
}
|
|
35040
|
+
return false;
|
|
35041
|
+
}
|
|
34885
35042
|
const nodeToVisit = [];
|
|
34886
35043
|
const appendNodeToVisit = (node) => {
|
|
34887
35044
|
nodeToVisit.push(node);
|
|
@@ -34913,6 +35070,9 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
34913
35070
|
const members = node.members;
|
|
34914
35071
|
for (const member of members) {
|
|
34915
35072
|
if (ts.isConstructorDeclaration(member)) {
|
|
35073
|
+
if (isAllowedConstructor(member)) {
|
|
35074
|
+
continue;
|
|
35075
|
+
}
|
|
34916
35076
|
const fixAsStaticNew = {
|
|
34917
35077
|
fixName: "overriddenSchemaConstructor_static",
|
|
34918
35078
|
description: "Rewrite using the static 'new' pattern",
|
|
@@ -35321,6 +35481,7 @@ var strictBooleanExpressions = createDiagnostic({
|
|
|
35321
35481
|
for (const nodeToCheck of nodes) {
|
|
35322
35482
|
if (!nodeToCheck) continue;
|
|
35323
35483
|
if (!conditionChecks.has(nodeToCheck.parent)) continue;
|
|
35484
|
+
if (!ts.isExpression(nodeToCheck)) continue;
|
|
35324
35485
|
const nodeType = typeChecker.getTypeAtLocation(nodeToCheck);
|
|
35325
35486
|
const constrainedType = typeChecker.getBaseConstraintOfType(nodeType);
|
|
35326
35487
|
let typesToCheck = [constrainedType || nodeType];
|
|
@@ -35710,6 +35871,7 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
35710
35871
|
|
|
35711
35872
|
// src/diagnostics.ts
|
|
35712
35873
|
var diagnostics = [
|
|
35874
|
+
anyUnknownInErrorContext,
|
|
35713
35875
|
catchUnfailableEffect,
|
|
35714
35876
|
classSelfMismatch,
|
|
35715
35877
|
duplicatePackage,
|