@typespec/compiler 1.10.0-dev.1 → 1.10.0-dev.10
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/dist/generated-defs/TypeSpec.Prototypes.ts-test.js +1 -1
- package/dist/generated-defs/TypeSpec.Prototypes.ts-test.js.map +1 -1
- package/dist/generated-defs/TypeSpec.ts-test.js +1 -1
- package/dist/generated-defs/TypeSpec.ts-test.js.map +1 -1
- package/dist/manifest.js +2 -2
- package/dist/src/core/binder.d.ts.map +1 -1
- package/dist/src/core/binder.js +33 -19
- package/dist/src/core/binder.js.map +1 -1
- package/dist/src/core/checker.d.ts.map +1 -1
- package/dist/src/core/checker.js +594 -67
- package/dist/src/core/checker.js.map +1 -1
- package/dist/src/core/cli/actions/info/emitter-options.d.ts +40 -0
- package/dist/src/core/cli/actions/info/emitter-options.d.ts.map +1 -0
- package/dist/src/core/cli/actions/info/emitter-options.js +345 -0
- package/dist/src/core/cli/actions/info/emitter-options.js.map +1 -0
- package/dist/src/core/cli/actions/info.d.ts +5 -2
- package/dist/src/core/cli/actions/info.d.ts.map +1 -1
- package/dist/src/core/cli/actions/info.js +6 -2
- package/dist/src/core/cli/actions/info.js.map +1 -1
- package/dist/src/core/cli/cli.js +43 -4
- package/dist/src/core/cli/cli.js.map +1 -1
- package/dist/src/core/helpers/string-template-utils.d.ts.map +1 -1
- package/dist/src/core/helpers/string-template-utils.js +7 -4
- package/dist/src/core/helpers/string-template-utils.js.map +1 -1
- package/dist/src/core/helpers/syntax-utils.d.ts.map +1 -1
- package/dist/src/core/helpers/syntax-utils.js +11 -3
- package/dist/src/core/helpers/syntax-utils.js.map +1 -1
- package/dist/src/core/helpers/type-name-utils.d.ts.map +1 -1
- package/dist/src/core/helpers/type-name-utils.js +13 -0
- package/dist/src/core/helpers/type-name-utils.js.map +1 -1
- package/dist/src/core/js-marshaller.d.ts +4 -2
- package/dist/src/core/js-marshaller.d.ts.map +1 -1
- package/dist/src/core/js-marshaller.js +96 -6
- package/dist/src/core/js-marshaller.js.map +1 -1
- package/dist/src/core/messages.d.ts +123 -32
- package/dist/src/core/messages.d.ts.map +1 -1
- package/dist/src/core/messages.js +29 -6
- package/dist/src/core/messages.js.map +1 -1
- package/dist/src/core/modifiers.d.ts +14 -0
- package/dist/src/core/modifiers.d.ts.map +1 -0
- package/dist/src/core/modifiers.js +166 -0
- package/dist/src/core/modifiers.js.map +1 -0
- package/dist/src/core/module-host.d.ts +5 -0
- package/dist/src/core/module-host.d.ts.map +1 -0
- package/dist/src/core/module-host.js +12 -0
- package/dist/src/core/module-host.js.map +1 -0
- package/dist/src/core/name-resolver.d.ts.map +1 -1
- package/dist/src/core/name-resolver.js +32 -0
- package/dist/src/core/name-resolver.js.map +1 -1
- package/dist/src/core/parser.d.ts.map +1 -1
- package/dist/src/core/parser.js +154 -101
- package/dist/src/core/parser.js.map +1 -1
- package/dist/src/core/program.d.ts.map +1 -1
- package/dist/src/core/program.js +5 -11
- package/dist/src/core/program.js.map +1 -1
- package/dist/src/core/scanner.d.ts +48 -48
- package/dist/src/core/scanner.d.ts.map +1 -1
- package/dist/src/core/scanner.js +55 -56
- package/dist/src/core/scanner.js.map +1 -1
- package/dist/src/core/semantic-walker.d.ts +3 -3
- package/dist/src/core/semantic-walker.d.ts.map +1 -1
- package/dist/src/core/semantic-walker.js +63 -44
- package/dist/src/core/semantic-walker.js.map +1 -1
- package/dist/src/core/source-loader.d.ts.map +1 -1
- package/dist/src/core/source-loader.js +4 -11
- package/dist/src/core/source-loader.js.map +1 -1
- package/dist/src/core/type-relation-checker.d.ts.map +1 -1
- package/dist/src/core/type-relation-checker.js +157 -10
- package/dist/src/core/type-relation-checker.js.map +1 -1
- package/dist/src/core/types.d.ts +215 -32
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/types.js +2 -0
- package/dist/src/core/types.js.map +1 -1
- package/dist/src/experimental/mutators.js +3 -3
- package/dist/src/experimental/mutators.js.map +1 -1
- package/dist/src/experimental/typekit/index.d.ts.map +1 -1
- package/dist/src/experimental/typekit/index.js.map +1 -1
- package/dist/src/formatter/print/printer.d.ts +2 -2
- package/dist/src/formatter/print/printer.d.ts.map +1 -1
- package/dist/src/formatter/print/printer.js +55 -5
- package/dist/src/formatter/print/printer.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/examples.d.ts +10 -3
- package/dist/src/lib/examples.d.ts.map +1 -1
- package/dist/src/lib/examples.js +22 -7
- package/dist/src/lib/examples.js.map +1 -1
- package/dist/src/server/completion.js +1 -0
- package/dist/src/server/completion.js.map +1 -1
- package/dist/src/server/server-compile-manager.js +1 -1
- package/dist/src/server/server-compile-manager.js.map +1 -1
- package/dist/src/server/tmlanguage.d.ts +1 -1
- package/dist/src/server/tmlanguage.d.ts.map +1 -1
- package/dist/src/server/tmlanguage.js +39 -29
- package/dist/src/server/tmlanguage.js.map +1 -1
- package/dist/src/server/type-signature.js +19 -0
- package/dist/src/server/type-signature.js.map +1 -1
- package/dist/src/utils/fs-utils.d.ts.map +1 -1
- package/dist/src/utils/fs-utils.js +1 -1
- package/dist/src/utils/fs-utils.js.map +1 -1
- package/dist/typespec.tmLanguage +103 -53
- package/lib/prototypes.tsp +2 -1
- package/package.json +13 -14
- package/templates/__snapshots__/emitter-ts/eslint.config.js +10 -1
- package/templates/__snapshots__/emitter-ts/package.json +1 -2
- package/templates/__snapshots__/emitter-ts/test/test-host.ts +7 -34
- package/templates/__snapshots__/library-ts/eslint.config.js +10 -1
- package/templates/__snapshots__/library-ts/package.json +1 -2
- package/templates/__snapshots__/library-ts/test/decorators.test.ts +18 -23
- package/templates/__snapshots__/library-ts/test/test-host.ts +5 -15
- package/templates/emitter-ts/eslint.config.js +10 -1
- package/templates/emitter-ts/package.json +1 -2
- package/templates/emitter-ts/test/test-host.ts.mu +7 -34
- package/templates/library-ts/eslint.config.js +10 -1
- package/templates/library-ts/package.json +1 -2
- package/templates/library-ts/test/decorators.test.ts.mu +18 -23
- package/templates/library-ts/test/test-host.ts.mu +5 -15
package/dist/src/core/checker.js
CHANGED
|
@@ -7,13 +7,15 @@ import { createSymbol, getSymNode } from "./binder.js";
|
|
|
7
7
|
import { createChangeIdentifierCodeFix } from "./compiler-code-fixes/change-identifier.codefix.js";
|
|
8
8
|
import { createModelToObjectValueCodeFix, createTupleToArrayValueCodeFix, } from "./compiler-code-fixes/convert-to-value.codefix.js";
|
|
9
9
|
import { getDeprecationDetails, markDeprecated } from "./deprecation.js";
|
|
10
|
-
import { compilerAssert, ignoreDiagnostics, reportDeprecated } from "./diagnostics.js";
|
|
10
|
+
import { compilerAssert, createDiagnosticCollector, ignoreDiagnostics, reportDeprecated, } from "./diagnostics.js";
|
|
11
11
|
import { validateInheritanceDiscriminatedUnions } from "./helpers/discriminator-utils.js";
|
|
12
|
+
import { getLocationContext } from "./helpers/location-context.js";
|
|
12
13
|
import { explainStringTemplateNotSerializable } from "./helpers/string-template-utils.js";
|
|
13
14
|
import { typeReferenceToString } from "./helpers/syntax-utils.js";
|
|
14
15
|
import { getEntityName, getTypeName } from "./helpers/type-name-utils.js";
|
|
15
|
-
import {
|
|
16
|
+
import { marshalTypeForJs, unmarshalJsToValue } from "./js-marshaller.js";
|
|
16
17
|
import { createDiagnostic } from "./messages.js";
|
|
18
|
+
import { checkModifiers } from "./modifiers.js";
|
|
17
19
|
import { Numeric } from "./numeric.js";
|
|
18
20
|
import { exprIsBareIdentifier, getFirstAncestor, getIdentifierContext, hasParseError, visitChildren, } from "./parser.js";
|
|
19
21
|
import { createTypeRelationChecker } from "./type-relation-checker.js";
|
|
@@ -175,6 +177,7 @@ export function createChecker(program, resolver) {
|
|
|
175
177
|
nullType,
|
|
176
178
|
anyType: unknownType,
|
|
177
179
|
voidType,
|
|
180
|
+
unknownType,
|
|
178
181
|
typePrototype,
|
|
179
182
|
createType,
|
|
180
183
|
createAndFinishType,
|
|
@@ -228,6 +231,16 @@ export function createChecker(program, resolver) {
|
|
|
228
231
|
declarations: [],
|
|
229
232
|
node: undefined, // TODO: is this correct?
|
|
230
233
|
});
|
|
234
|
+
const internalDecorators = [
|
|
235
|
+
typespecNamespaceBinding.exports?.get("@indexer"),
|
|
236
|
+
typespecNamespaceBinding.exports?.get("@docFromComment"),
|
|
237
|
+
typespecNamespaceBinding.exports?.get("Prototypes")?.exports?.get("@getter"),
|
|
238
|
+
];
|
|
239
|
+
for (const decorator of internalDecorators) {
|
|
240
|
+
if (decorator) {
|
|
241
|
+
mutate(decorator).flags |= 8388608 /* SymbolFlags.Internal */;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
231
244
|
// Until we have an `unit` type for `null`
|
|
232
245
|
mutate(resolver.symbols.null).type = nullType;
|
|
233
246
|
getSymbolLinks(resolver.symbols.null).type = nullType;
|
|
@@ -346,7 +359,7 @@ export function createChecker(program, resolver) {
|
|
|
346
359
|
function getValueForNode(node, mapperOrContext, constraint) {
|
|
347
360
|
const ctx = CheckContext.from(mapperOrContext);
|
|
348
361
|
const initial = checkNode(ctx, node, constraint);
|
|
349
|
-
if (initial === null) {
|
|
362
|
+
if (initial === null || initial === errorType) {
|
|
350
363
|
return null;
|
|
351
364
|
}
|
|
352
365
|
let entity;
|
|
@@ -360,6 +373,8 @@ export function createChecker(program, resolver) {
|
|
|
360
373
|
return null;
|
|
361
374
|
}
|
|
362
375
|
if (isValue(entity)) {
|
|
376
|
+
if (entity.valueKind === "Function")
|
|
377
|
+
return entity;
|
|
363
378
|
return constraint ? inferScalarsFromConstraints(entity, constraint.type) : entity;
|
|
364
379
|
}
|
|
365
380
|
// If a template parameter that can be a value is used in a template declaration then we allow it but we return null because we don't have an actual value.
|
|
@@ -420,9 +435,8 @@ export function createChecker(program, resolver) {
|
|
|
420
435
|
case "UnionVariant":
|
|
421
436
|
return getValueFromIndeterminate(type.type, constraint, node);
|
|
422
437
|
case "Intrinsic":
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return checkNullValue(type, constraint, node);
|
|
438
|
+
if (type.name === "null") {
|
|
439
|
+
return checkNullValue(type, constraint, node);
|
|
426
440
|
}
|
|
427
441
|
return type;
|
|
428
442
|
default:
|
|
@@ -477,8 +491,8 @@ export function createChecker(program, resolver) {
|
|
|
477
491
|
* For nodes that can be both type or values(e.g. string), the value will be returned if the constraint expect a value of that type even if the constrain also allows the type.
|
|
478
492
|
* This means that if the constraint is `string | valueof string` passing `"abc"` will send the value `"abc"` and not the type `"abc"`.
|
|
479
493
|
*/
|
|
480
|
-
function getTypeOrValueForNode(node,
|
|
481
|
-
const ctx = CheckContext.from(
|
|
494
|
+
function getTypeOrValueForNode(node, contextOrMapper, constraint) {
|
|
495
|
+
const ctx = CheckContext.from(contextOrMapper);
|
|
482
496
|
const valueConstraint = extractValueOfConstraints(constraint);
|
|
483
497
|
const entity = checkNode(ctx, node, valueConstraint);
|
|
484
498
|
if (entity === null) {
|
|
@@ -507,6 +521,12 @@ export function createChecker(program, resolver) {
|
|
|
507
521
|
reportCheckerDiagnostics(valueDiagnostics);
|
|
508
522
|
return result;
|
|
509
523
|
}
|
|
524
|
+
else {
|
|
525
|
+
const canBeType = constraint?.constraint.type !== undefined;
|
|
526
|
+
// If the node _must_ resolve to a value, we will return it unconstrained, so that we will at least produce
|
|
527
|
+
// a value. If it _can_ be a type, we already failed the value constraint, so we return the type as is.
|
|
528
|
+
return canBeType ? entity.type : getValueFromIndeterminate(entity.type, undefined, node);
|
|
529
|
+
}
|
|
510
530
|
}
|
|
511
531
|
return entity.type;
|
|
512
532
|
}
|
|
@@ -571,6 +591,8 @@ export function createChecker(program, resolver) {
|
|
|
571
591
|
return checkDecoratorDeclaration(ctx, node);
|
|
572
592
|
case SyntaxKind.FunctionDeclarationStatement:
|
|
573
593
|
return checkFunctionDeclaration(ctx, node);
|
|
594
|
+
case SyntaxKind.FunctionTypeExpression:
|
|
595
|
+
return checkFunctionTypeExpression(ctx, node);
|
|
574
596
|
case SyntaxKind.TypeReference:
|
|
575
597
|
return checkTypeOrValueReference(ctx, node);
|
|
576
598
|
case SyntaxKind.TemplateArgument:
|
|
@@ -711,6 +733,7 @@ export function createChecker(program, resolver) {
|
|
|
711
733
|
* @param node Node.
|
|
712
734
|
* @param mapper Type mapper for template instantiation context.
|
|
713
735
|
* @param instantiateTemplate If templated type should be instantiated if they haven't yet.
|
|
736
|
+
* @param allowFunctions If functions are allowed as types.
|
|
714
737
|
* @returns Resolved type.
|
|
715
738
|
*/
|
|
716
739
|
function checkTypeReference(ctx, node, instantiateTemplate = true) {
|
|
@@ -726,6 +749,7 @@ export function createChecker(program, resolver) {
|
|
|
726
749
|
* @param node Node.
|
|
727
750
|
* @param mapper Type mapper for template instantiation context.
|
|
728
751
|
* @param instantiateTemplate If templated type should be instantiated if they haven't yet.
|
|
752
|
+
* @param allowFunctions If functions are allowed as types.
|
|
729
753
|
* @returns Resolved type.
|
|
730
754
|
*/
|
|
731
755
|
function checkTypeOrValueReference(ctx, node, instantiateTemplate = true) {
|
|
@@ -953,6 +977,7 @@ export function createChecker(program, resolver) {
|
|
|
953
977
|
* @param node Node
|
|
954
978
|
* @param mapper Type mapper for template instantiation context.
|
|
955
979
|
* @param instantiateTemplates If a templated type should be instantiated if not yet @default true
|
|
980
|
+
* @param allowFunctions If functions are allowed as types. @default false
|
|
956
981
|
* @returns resolved type.
|
|
957
982
|
*/
|
|
958
983
|
function checkTypeReferenceSymbol(ctx, sym, node, instantiateTemplates = true) {
|
|
@@ -983,8 +1008,7 @@ export function createChecker(program, resolver) {
|
|
|
983
1008
|
return errorType;
|
|
984
1009
|
}
|
|
985
1010
|
if (sym.flags & 2048 /* SymbolFlags.Function */) {
|
|
986
|
-
|
|
987
|
-
return errorType;
|
|
1011
|
+
return getValueForNode(sym.declarations[0], ctx);
|
|
988
1012
|
}
|
|
989
1013
|
const argumentNodes = node.kind === SyntaxKind.TypeReference ? node.arguments : [];
|
|
990
1014
|
const symbolLinks = getSymbolLinks(sym);
|
|
@@ -1141,7 +1165,7 @@ export function createChecker(program, resolver) {
|
|
|
1141
1165
|
function checkDeclaredType(ctx, sym, node) {
|
|
1142
1166
|
return getTypeForTypeOrIndeterminate(checkDeclaredTypeOrIndeterminate(ctx, sym, node));
|
|
1143
1167
|
}
|
|
1144
|
-
function getOrInstantiateTemplate(ctx, templateNode, params, args, source, parentMapper,
|
|
1168
|
+
function getOrInstantiateTemplate(ctx, templateNode, params, args, source, parentMapper, instantiateTemplates = true) {
|
|
1145
1169
|
const symbolLinks = templateNode.kind === SyntaxKind.OperationStatement &&
|
|
1146
1170
|
templateNode.parent.kind === SyntaxKind.InterfaceStatement
|
|
1147
1171
|
? getSymbolLinksForMember(templateNode)
|
|
@@ -1161,7 +1185,7 @@ export function createChecker(program, resolver) {
|
|
|
1161
1185
|
if (cached) {
|
|
1162
1186
|
return cached;
|
|
1163
1187
|
}
|
|
1164
|
-
if (
|
|
1188
|
+
if (instantiateTemplates) {
|
|
1165
1189
|
return instantiateTemplate(ctx.withMapper(mapper), symbolLinks.instantiations, templateNode, params);
|
|
1166
1190
|
}
|
|
1167
1191
|
else {
|
|
@@ -1331,12 +1355,10 @@ export function createChecker(program, resolver) {
|
|
|
1331
1355
|
// we're not instantiating this operation and we've already checked it
|
|
1332
1356
|
return links.declaredType;
|
|
1333
1357
|
}
|
|
1358
|
+
checkModifiers(program, node);
|
|
1334
1359
|
const namespace = getParentNamespaceType(node);
|
|
1335
1360
|
compilerAssert(namespace, `Decorator ${node.id.sv} should have resolved a namespace or found the global namespace.`);
|
|
1336
1361
|
const name = node.id.sv;
|
|
1337
|
-
if (!(node.modifierFlags & 2 /* ModifierFlags.Extern */)) {
|
|
1338
|
-
reportCheckerDiagnostic(createDiagnostic({ code: "decorator-extern", target: node }));
|
|
1339
|
-
}
|
|
1340
1362
|
const implementation = symbol.value;
|
|
1341
1363
|
if (implementation === undefined) {
|
|
1342
1364
|
reportCheckerDiagnostic(createDiagnostic({ code: "missing-implementation", target: node }));
|
|
@@ -1355,8 +1377,67 @@ export function createChecker(program, resolver) {
|
|
|
1355
1377
|
return decoratorType;
|
|
1356
1378
|
}
|
|
1357
1379
|
function checkFunctionDeclaration(ctx, node) {
|
|
1358
|
-
|
|
1359
|
-
|
|
1380
|
+
const mergedSymbol = getMergedSymbol(node.symbol);
|
|
1381
|
+
const links = getSymbolLinks(mergedSymbol);
|
|
1382
|
+
if (links.value !== undefined) {
|
|
1383
|
+
return links.value;
|
|
1384
|
+
}
|
|
1385
|
+
checkModifiers(program, node);
|
|
1386
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
1387
|
+
code: "experimental-feature",
|
|
1388
|
+
messageId: "functionDeclarations",
|
|
1389
|
+
target: node,
|
|
1390
|
+
}));
|
|
1391
|
+
const namespace = getParentNamespaceType(node);
|
|
1392
|
+
compilerAssert(namespace, `Function ${node.id.sv} should have resolved a declared namespace or the global namespace.`);
|
|
1393
|
+
const name = node.id.sv;
|
|
1394
|
+
const implementation = mergedSymbol.value;
|
|
1395
|
+
if (implementation === undefined) {
|
|
1396
|
+
reportCheckerDiagnostic(createDiagnostic({ code: "missing-implementation", target: node }));
|
|
1397
|
+
}
|
|
1398
|
+
const parameters = node.parameters.map((x) => checkFunctionParameter(ctx, x, true));
|
|
1399
|
+
const returnType = node.returnType
|
|
1400
|
+
? getParamConstraintEntityForNode(ctx, node.returnType)
|
|
1401
|
+
: {
|
|
1402
|
+
entityKind: "MixedParameterConstraint",
|
|
1403
|
+
type: unknownType,
|
|
1404
|
+
};
|
|
1405
|
+
const functionValue = createValue({
|
|
1406
|
+
entityKind: "Value",
|
|
1407
|
+
valueKind: "Function",
|
|
1408
|
+
name,
|
|
1409
|
+
type: createAndFinishType({
|
|
1410
|
+
kind: "FunctionType",
|
|
1411
|
+
parameters,
|
|
1412
|
+
returnType,
|
|
1413
|
+
}),
|
|
1414
|
+
parameters,
|
|
1415
|
+
returnType,
|
|
1416
|
+
namespace,
|
|
1417
|
+
node,
|
|
1418
|
+
implementation: implementation ??
|
|
1419
|
+
Object.assign(() => getDefaultFunctionResult(returnType), {
|
|
1420
|
+
isDefaultFunctionImplementation: true,
|
|
1421
|
+
}),
|
|
1422
|
+
}, unknownType);
|
|
1423
|
+
namespace.functionDeclarations.set(name, functionValue);
|
|
1424
|
+
links.value = functionValue;
|
|
1425
|
+
return functionValue;
|
|
1426
|
+
}
|
|
1427
|
+
function checkFunctionTypeExpression(ctx, node) {
|
|
1428
|
+
const parameters = node.parameters.map((param) => checkFunctionParameter(ctx, param, true));
|
|
1429
|
+
const returnType = node.returnType
|
|
1430
|
+
? getParamConstraintEntityForNode(ctx, node.returnType)
|
|
1431
|
+
: {
|
|
1432
|
+
entityKind: "MixedParameterConstraint",
|
|
1433
|
+
type: unknownType,
|
|
1434
|
+
};
|
|
1435
|
+
return createAndFinishType({
|
|
1436
|
+
kind: "FunctionType",
|
|
1437
|
+
node,
|
|
1438
|
+
parameters,
|
|
1439
|
+
returnType,
|
|
1440
|
+
});
|
|
1360
1441
|
}
|
|
1361
1442
|
function checkFunctionParameter(ctx, node, mixed) {
|
|
1362
1443
|
const links = getSymbolLinks(node.symbol);
|
|
@@ -1512,6 +1593,7 @@ export function createChecker(program, resolver) {
|
|
|
1512
1593
|
type = initializeTypeForNamespace(node);
|
|
1513
1594
|
}
|
|
1514
1595
|
if (node.kind === SyntaxKind.NamespaceStatement) {
|
|
1596
|
+
checkModifiers(program, node);
|
|
1515
1597
|
if (isArray(node.statements)) {
|
|
1516
1598
|
node.statements.forEach((x) => checkNode(ctx, x));
|
|
1517
1599
|
}
|
|
@@ -1619,6 +1701,9 @@ export function createChecker(program, resolver) {
|
|
|
1619
1701
|
return links.declaredType;
|
|
1620
1702
|
}
|
|
1621
1703
|
}
|
|
1704
|
+
if (ctx.mapper === undefined) {
|
|
1705
|
+
checkModifiers(program, node);
|
|
1706
|
+
}
|
|
1622
1707
|
if (ctx.mapper === undefined && inInterface) {
|
|
1623
1708
|
compilerAssert(parentInterface, "Operation in interface should already have been checked.", node.parent);
|
|
1624
1709
|
}
|
|
@@ -1979,7 +2064,7 @@ export function createChecker(program, resolver) {
|
|
|
1979
2064
|
return undefined;
|
|
1980
2065
|
}
|
|
1981
2066
|
const ctorType = checkCallExpressionTarget(CheckContext.DEFAULT, callExpNode);
|
|
1982
|
-
if (ctorType?.kind !== "ScalarConstructor") {
|
|
2067
|
+
if (ctorType?.entityKind !== "Type" || ctorType?.kind !== "ScalarConstructor") {
|
|
1983
2068
|
return undefined;
|
|
1984
2069
|
}
|
|
1985
2070
|
const argIndex = callExpNode.arguments.findIndex((n) => n === argNode);
|
|
@@ -2209,12 +2294,15 @@ export function createChecker(program, resolver) {
|
|
|
2209
2294
|
case IdentifierKind.Decorator:
|
|
2210
2295
|
// Only return decorators and namespaces when completing decorator
|
|
2211
2296
|
return !!(sym.flags & (512 /* SymbolFlags.Decorator */ | 256 /* SymbolFlags.Namespace */));
|
|
2297
|
+
case IdentifierKind.Function:
|
|
2298
|
+
// Only return functions and namespaces when completing function calls
|
|
2299
|
+
return !!(sym.flags & (2048 /* SymbolFlags.Function */ | 256 /* SymbolFlags.Namespace */));
|
|
2212
2300
|
case IdentifierKind.Using:
|
|
2213
2301
|
// Only return namespaces when completing using
|
|
2214
2302
|
return !!(sym.flags & 256 /* SymbolFlags.Namespace */);
|
|
2215
2303
|
case IdentifierKind.TypeReference:
|
|
2216
|
-
// Do not return
|
|
2217
|
-
return !(sym.flags &
|
|
2304
|
+
// Do not return decorators when completing types
|
|
2305
|
+
return !(sym.flags & 512 /* SymbolFlags.Decorator */);
|
|
2218
2306
|
case IdentifierKind.TemplateArgument:
|
|
2219
2307
|
return !!(sym.flags & 1024 /* SymbolFlags.TemplateParameter */);
|
|
2220
2308
|
default:
|
|
@@ -2239,6 +2327,7 @@ export function createChecker(program, resolver) {
|
|
|
2239
2327
|
referenceSymCache.has(node)) {
|
|
2240
2328
|
return referenceSymCache.get(node);
|
|
2241
2329
|
}
|
|
2330
|
+
resolvedOptions.locationContext ??= getLocationContext(program, node);
|
|
2242
2331
|
const sym = resolveTypeReferenceSymInternal(ctx, node, resolvedOptions);
|
|
2243
2332
|
if (!resolvedOptions.resolveDeclarationOfTemplate) {
|
|
2244
2333
|
referenceSymCache.set(node, sym);
|
|
@@ -2271,8 +2360,9 @@ export function createChecker(program, resolver) {
|
|
|
2271
2360
|
reportAmbiguousIdentifier(node, links.ambiguousSymbols);
|
|
2272
2361
|
}
|
|
2273
2362
|
}
|
|
2274
|
-
const sym = links.resolvedSymbol;
|
|
2275
|
-
|
|
2363
|
+
const sym = links.resolvedSymbol?.symbolSource ?? links.resolvedSymbol;
|
|
2364
|
+
checkSymbolAccess(options.locationContext, node, sym);
|
|
2365
|
+
return sym;
|
|
2276
2366
|
}
|
|
2277
2367
|
else if (node.kind === SyntaxKind.MemberExpression) {
|
|
2278
2368
|
let base = resolveTypeReferenceSym(ctx, node.base, {
|
|
@@ -2284,22 +2374,42 @@ export function createChecker(program, resolver) {
|
|
|
2284
2374
|
}
|
|
2285
2375
|
// when resolving a type reference based on an alias, unwrap the alias.
|
|
2286
2376
|
if (base.flags & 128 /* SymbolFlags.Alias */) {
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2377
|
+
if (!options.resolveDeclarationOfTemplate && isTemplatedNode(getSymNode(base))) {
|
|
2378
|
+
// This is a bare identifier reference to a templated alias, so we need to actually check this type.
|
|
2379
|
+
const ty = checkTypeReferenceSymbol(ctx.withMapper(undefined), base, node.base,
|
|
2380
|
+
/* instantiateTemplates */ true);
|
|
2381
|
+
base = lateBindContainer(ty, base);
|
|
2382
|
+
if (base?.members) {
|
|
2383
|
+
switch (ty.kind) {
|
|
2384
|
+
case "Model":
|
|
2385
|
+
case "Union":
|
|
2386
|
+
case "Interface":
|
|
2387
|
+
case "Enum":
|
|
2388
|
+
case "Scalar":
|
|
2389
|
+
lateBindMembers(ty);
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
if (!base)
|
|
2393
|
+
return undefined;
|
|
2394
|
+
}
|
|
2395
|
+
else {
|
|
2396
|
+
const aliasedSym = getAliasedSymbol(ctx, base);
|
|
2397
|
+
if (!aliasedSym) {
|
|
2398
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2399
|
+
code: "invalid-ref",
|
|
2400
|
+
messageId: "node",
|
|
2401
|
+
format: {
|
|
2402
|
+
id: node.id.sv,
|
|
2403
|
+
nodeName: base.declarations[0]
|
|
2404
|
+
? SyntaxKind[base.declarations[0].kind]
|
|
2405
|
+
: "Unknown node",
|
|
2406
|
+
},
|
|
2407
|
+
target: node,
|
|
2408
|
+
}));
|
|
2409
|
+
return undefined;
|
|
2410
|
+
}
|
|
2411
|
+
base = aliasedSym;
|
|
2301
2412
|
}
|
|
2302
|
-
base = aliasedSym;
|
|
2303
2413
|
}
|
|
2304
2414
|
else if (!options.resolveDeclarationOfTemplate && isTemplatedNode(getSymNode(base))) {
|
|
2305
2415
|
const baseSym = getContainerTemplateSymbol(ctx, base, node.base);
|
|
@@ -2308,10 +2418,47 @@ export function createChecker(program, resolver) {
|
|
|
2308
2418
|
}
|
|
2309
2419
|
base = baseSym;
|
|
2310
2420
|
}
|
|
2311
|
-
|
|
2421
|
+
const sym = resolveMemberInContainer(base, node, options);
|
|
2422
|
+
checkSymbolAccess(options.locationContext, node, sym);
|
|
2423
|
+
return sym;
|
|
2312
2424
|
}
|
|
2313
2425
|
compilerAssert(false, `Unknown type reference kind "${SyntaxKind[node.kind]}"`, node);
|
|
2314
2426
|
}
|
|
2427
|
+
function checkSymbolAccess(sourceLocation, node, symbol) {
|
|
2428
|
+
if (!symbol)
|
|
2429
|
+
return;
|
|
2430
|
+
const isInternalDeclaration = (symbol.flags & (8388608 /* SymbolFlags.Internal */ | 1048576 /* SymbolFlags.Declaration */)) ===
|
|
2431
|
+
(8388608 /* SymbolFlags.Internal */ | 1048576 /* SymbolFlags.Declaration */);
|
|
2432
|
+
if (isInternalDeclaration) {
|
|
2433
|
+
// The source location can access internal declaration symbols if:
|
|
2434
|
+
// 1. The source location is synthetic.
|
|
2435
|
+
// 2. The source location is in the compiler standard library.
|
|
2436
|
+
// 3. SOME declaration of the target symbol meets the following:
|
|
2437
|
+
// 1. The source location is in the user project, and the symbol is also declared in the user project.
|
|
2438
|
+
// 2. The source location is in a library, and the symbol is also in the same library.
|
|
2439
|
+
if (sourceLocation.type === "synthetic" || sourceLocation.type === "compiler") {
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
const isDeclaredInCompatibleLocation = symbol.declarations.some((decl) => {
|
|
2443
|
+
const declLocation = getLocationContext(program, decl);
|
|
2444
|
+
if (declLocation.type !== sourceLocation.type)
|
|
2445
|
+
return false;
|
|
2446
|
+
// Both are project
|
|
2447
|
+
if (declLocation.type === "project")
|
|
2448
|
+
return true;
|
|
2449
|
+
// Both are library, use reference equality to check if they are the same library.
|
|
2450
|
+
return declLocation === sourceLocation;
|
|
2451
|
+
});
|
|
2452
|
+
if (isDeclaredInCompatibleLocation)
|
|
2453
|
+
return;
|
|
2454
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2455
|
+
code: "invalid-ref",
|
|
2456
|
+
messageId: "internal",
|
|
2457
|
+
format: { id: symbol.name },
|
|
2458
|
+
target: node,
|
|
2459
|
+
}));
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2315
2462
|
function reportAmbiguousIdentifier(node, symbols) {
|
|
2316
2463
|
const duplicateNames = symbols.map((s) => getFullyQualifiedSymbolName(s, { useGlobalPrefixAtTopLevel: true }));
|
|
2317
2464
|
program.reportDiagnostic(createDiagnostic({
|
|
@@ -2699,6 +2846,9 @@ export function createChecker(program, resolver) {
|
|
|
2699
2846
|
// we're not instantiating this model and we've already checked it
|
|
2700
2847
|
return links.declaredType;
|
|
2701
2848
|
}
|
|
2849
|
+
if (ctx.mapper === undefined) {
|
|
2850
|
+
checkModifiers(program, node);
|
|
2851
|
+
}
|
|
2702
2852
|
checkTemplateDeclaration(ctx, node);
|
|
2703
2853
|
const decorators = [];
|
|
2704
2854
|
const type = createType({
|
|
@@ -3109,17 +3259,68 @@ export function createChecker(program, resolver) {
|
|
|
3109
3259
|
}, literalType);
|
|
3110
3260
|
}
|
|
3111
3261
|
function checkCallExpressionTarget(ctx, node) {
|
|
3112
|
-
const target =
|
|
3113
|
-
if (target.
|
|
3114
|
-
|
|
3262
|
+
const target = checkTypeOrValueReference(ctx, node.target);
|
|
3263
|
+
if (target.entityKind === "Type") {
|
|
3264
|
+
if (target.kind === "Scalar" || target.kind === "ScalarConstructor") {
|
|
3265
|
+
return target;
|
|
3266
|
+
}
|
|
3267
|
+
else if (target.kind === "TemplateParameter") {
|
|
3268
|
+
const callable = target.constraint && constraintIsCallable(target.constraint);
|
|
3269
|
+
if (!callable) {
|
|
3270
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3271
|
+
code: "non-callable",
|
|
3272
|
+
messageId: "templateParameter",
|
|
3273
|
+
format: {
|
|
3274
|
+
name: target.node.id.sv,
|
|
3275
|
+
constraint: target.constraint
|
|
3276
|
+
? getEntityName(target.constraint, { printable: true })
|
|
3277
|
+
: "unknown",
|
|
3278
|
+
},
|
|
3279
|
+
target: node.target,
|
|
3280
|
+
}));
|
|
3281
|
+
}
|
|
3282
|
+
return null;
|
|
3283
|
+
}
|
|
3115
3284
|
}
|
|
3116
|
-
else {
|
|
3285
|
+
else if (target.entityKind === "Value") {
|
|
3286
|
+
if (target.valueKind === "Function") {
|
|
3287
|
+
return target;
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
const kind = target.entityKind === "Type"
|
|
3291
|
+
? target.kind
|
|
3292
|
+
: target.entityKind === "Indeterminate"
|
|
3293
|
+
? target.type.kind
|
|
3294
|
+
: target.valueKind;
|
|
3295
|
+
if (!isErrorType(target)) {
|
|
3117
3296
|
reportCheckerDiagnostic(createDiagnostic({
|
|
3118
3297
|
code: "non-callable",
|
|
3119
|
-
format: { type:
|
|
3298
|
+
format: { type: kind },
|
|
3120
3299
|
target: node.target,
|
|
3121
3300
|
}));
|
|
3122
|
-
|
|
3301
|
+
}
|
|
3302
|
+
return null;
|
|
3303
|
+
function constraintIsCallable(constraint) {
|
|
3304
|
+
compilerAssert(constraint.type || constraint.valueType, "Expected constraint to have type or value type");
|
|
3305
|
+
let callable = true;
|
|
3306
|
+
if (constraint.type) {
|
|
3307
|
+
callable &&= typeIsCallable(constraint.type);
|
|
3308
|
+
}
|
|
3309
|
+
if (constraint.valueType) {
|
|
3310
|
+
callable &&= constraint.valueType.kind === "FunctionType";
|
|
3311
|
+
}
|
|
3312
|
+
return callable;
|
|
3313
|
+
}
|
|
3314
|
+
function typeIsCallable(type) {
|
|
3315
|
+
switch (type.kind) {
|
|
3316
|
+
case "Scalar":
|
|
3317
|
+
case "ScalarConstructor":
|
|
3318
|
+
return true;
|
|
3319
|
+
case "Union":
|
|
3320
|
+
return [...type.variants.values()].every(typeIsCallable);
|
|
3321
|
+
default:
|
|
3322
|
+
return false;
|
|
3323
|
+
}
|
|
3123
3324
|
}
|
|
3124
3325
|
}
|
|
3125
3326
|
/** Check the arguments of the call expression are a single value of the given syntax. */
|
|
@@ -3244,9 +3445,13 @@ export function createChecker(program, resolver) {
|
|
|
3244
3445
|
if (target === null) {
|
|
3245
3446
|
return null;
|
|
3246
3447
|
}
|
|
3247
|
-
if (target.kind === "ScalarConstructor") {
|
|
3448
|
+
if (target.entityKind === "Type" && target.kind === "ScalarConstructor") {
|
|
3248
3449
|
return createScalarValue(ctx, node, target);
|
|
3249
3450
|
}
|
|
3451
|
+
else if (target.entityKind === "Value" && target.valueKind === "Function") {
|
|
3452
|
+
return checkFunctionCall(ctx, node, target);
|
|
3453
|
+
}
|
|
3454
|
+
compilerAssert(target.entityKind === "Type", "Expected type entity");
|
|
3250
3455
|
if (relation.areScalarsRelated(target, getStdType("string"))) {
|
|
3251
3456
|
return checkPrimitiveArg(node, target, "StringValue");
|
|
3252
3457
|
}
|
|
@@ -3265,6 +3470,264 @@ export function createChecker(program, resolver) {
|
|
|
3265
3470
|
return null;
|
|
3266
3471
|
}
|
|
3267
3472
|
}
|
|
3473
|
+
function checkFunctionCall(ctx, node, target) {
|
|
3474
|
+
const [satisfied, resolvedArgs] = checkFunctionCallArguments(ctx, node.arguments, target);
|
|
3475
|
+
const canCall = satisfied &&
|
|
3476
|
+
!ctx.hasFlags(CheckFlags.InTemplateDeclaration) &&
|
|
3477
|
+
!target.implementation.isDefaultFunctionImplementation;
|
|
3478
|
+
const fnCtx = createFunctionContext(program, node);
|
|
3479
|
+
if (!canCall) {
|
|
3480
|
+
return getDefaultFunctionResult(target.returnType);
|
|
3481
|
+
}
|
|
3482
|
+
const functionReturn = target.implementation(fnCtx, ...resolvedArgs);
|
|
3483
|
+
const returnIsEntity = typeof functionReturn === "object" &&
|
|
3484
|
+
functionReturn !== null &&
|
|
3485
|
+
"entityKind" in functionReturn &&
|
|
3486
|
+
(functionReturn.entityKind === "Type" ||
|
|
3487
|
+
functionReturn.entityKind === "Value" ||
|
|
3488
|
+
functionReturn.entityKind === "Indeterminate");
|
|
3489
|
+
// special case for when the return value is `undefined` and the return type is `void` or `valueof void`.
|
|
3490
|
+
if (functionReturn === undefined && isVoidReturn(target.returnType)) {
|
|
3491
|
+
return voidType;
|
|
3492
|
+
}
|
|
3493
|
+
const unmarshaled = returnIsEntity
|
|
3494
|
+
? functionReturn
|
|
3495
|
+
: unmarshalJsToValue(program, functionReturn, function onInvalid(value) {
|
|
3496
|
+
let valueSummary = String(value);
|
|
3497
|
+
if (valueSummary.length > 30) {
|
|
3498
|
+
valueSummary = valueSummary.slice(0, 27) + "...";
|
|
3499
|
+
}
|
|
3500
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3501
|
+
code: "function-return",
|
|
3502
|
+
messageId: "invalid-value",
|
|
3503
|
+
format: { value: valueSummary },
|
|
3504
|
+
target: node,
|
|
3505
|
+
}));
|
|
3506
|
+
});
|
|
3507
|
+
let result = unmarshaled;
|
|
3508
|
+
if (satisfied && result !== null)
|
|
3509
|
+
result = checkFunctionReturn(target, result, node);
|
|
3510
|
+
return result;
|
|
3511
|
+
}
|
|
3512
|
+
function isVoidReturn(constraint) {
|
|
3513
|
+
if (constraint.valueType) {
|
|
3514
|
+
return false;
|
|
3515
|
+
}
|
|
3516
|
+
if (constraint.type) {
|
|
3517
|
+
if (!isVoidType(constraint.type))
|
|
3518
|
+
return false;
|
|
3519
|
+
}
|
|
3520
|
+
return true;
|
|
3521
|
+
function isVoidType(type) {
|
|
3522
|
+
return type.kind === "Intrinsic" && type.name === "void";
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
/**
|
|
3526
|
+
* Produces the default function result when a function call cannot be completed.
|
|
3527
|
+
*
|
|
3528
|
+
* This produces `null` if the function has a value type constraint but no type constraint, `errorType`
|
|
3529
|
+
* otherwise (if the function _could_ return a Type).
|
|
3530
|
+
*
|
|
3531
|
+
* @param constraint - The function return constraint.
|
|
3532
|
+
* @returns
|
|
3533
|
+
*/
|
|
3534
|
+
function getDefaultFunctionResult(constraint) {
|
|
3535
|
+
if (constraint.valueType) {
|
|
3536
|
+
// If the function _can_ return a value, we will just return null. This is a bit of a hack, but it's the best fallback
|
|
3537
|
+
// for a function that could return a type or value, since returning a type would cause type-in-value errors.
|
|
3538
|
+
return null;
|
|
3539
|
+
}
|
|
3540
|
+
else {
|
|
3541
|
+
compilerAssert(constraint.type, "Expected function to have a return type when it did not have a value type constraint");
|
|
3542
|
+
// If for some reason we cannot evaluate the call, we will return the type constraint itself as a fallback.
|
|
3543
|
+
// This is the strongest thing we can do in the context of an error or a template declaration, since the result
|
|
3544
|
+
// of the function call must be assignable to the constraint, and by the transitive property if the constraint
|
|
3545
|
+
// is assignable in the context of evaluation, so will be the result of any valid evaluation of the implementation.
|
|
3546
|
+
// Technically, this isn't exactly ideal, since it could prevent function calls that return subtypes of the constraint
|
|
3547
|
+
// from assigning if the _result_ would be assignable. However, we have other cases where we check constraints in
|
|
3548
|
+
// templates to try to ensure that any instance will validate. We may need to revisit this in the future, but for
|
|
3549
|
+
// now, I am choosing strictness in the face of uncertainty.
|
|
3550
|
+
return constraint.type;
|
|
3551
|
+
}
|
|
3552
|
+
}
|
|
3553
|
+
function checkFunctionCallArguments(ctx, args, target) {
|
|
3554
|
+
let satisfied = true;
|
|
3555
|
+
const minArgs = target.parameters.filter((p) => !p.optional && !p.rest).length;
|
|
3556
|
+
const maxArgs = target.parameters[target.parameters.length - 1]?.rest
|
|
3557
|
+
? undefined
|
|
3558
|
+
: target.parameters.length;
|
|
3559
|
+
if (args.length < minArgs) {
|
|
3560
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3561
|
+
code: "invalid-argument-count",
|
|
3562
|
+
messageId: "atLeast",
|
|
3563
|
+
format: { actual: args.length.toString(), expected: minArgs.toString() },
|
|
3564
|
+
target: target.node,
|
|
3565
|
+
}));
|
|
3566
|
+
return [false, []];
|
|
3567
|
+
}
|
|
3568
|
+
else if (maxArgs !== undefined && args.length > maxArgs) {
|
|
3569
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3570
|
+
code: "invalid-argument-count",
|
|
3571
|
+
format: { actual: args.length.toString(), expected: maxArgs.toString() },
|
|
3572
|
+
target: target.node,
|
|
3573
|
+
}));
|
|
3574
|
+
// This error doesn't actually prevent us from checking the arguments and evaluating the function.
|
|
3575
|
+
}
|
|
3576
|
+
const collector = createDiagnosticCollector();
|
|
3577
|
+
const resolvedArgs = [];
|
|
3578
|
+
let idx = 0;
|
|
3579
|
+
for (const param of target.parameters) {
|
|
3580
|
+
if (param.rest) {
|
|
3581
|
+
const constraint = extractRestParamConstraint(param.type);
|
|
3582
|
+
if (!constraint) {
|
|
3583
|
+
satisfied = false;
|
|
3584
|
+
continue;
|
|
3585
|
+
}
|
|
3586
|
+
const restArgExpressions = args.slice(idx);
|
|
3587
|
+
const restArgs = restArgExpressions.map((arg) => getTypeOrValueForNode(arg, ctx, { kind: "argument", constraint }));
|
|
3588
|
+
if (restArgs.some((x) => x === null)) {
|
|
3589
|
+
satisfied = false;
|
|
3590
|
+
continue;
|
|
3591
|
+
}
|
|
3592
|
+
resolvedArgs.push(...restArgs.map((v, idx) => v !== null && isValue(v) ? marshalTypeForJs(v, undefined) : v));
|
|
3593
|
+
}
|
|
3594
|
+
else {
|
|
3595
|
+
const arg = args[idx++];
|
|
3596
|
+
if (!arg) {
|
|
3597
|
+
if (param.optional) {
|
|
3598
|
+
resolvedArgs.push(undefined);
|
|
3599
|
+
continue;
|
|
3600
|
+
}
|
|
3601
|
+
else {
|
|
3602
|
+
// No need to report a diagnostic here because we already reported one for
|
|
3603
|
+
// invalid argument counts above.
|
|
3604
|
+
satisfied = false;
|
|
3605
|
+
continue;
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
// Normal param
|
|
3609
|
+
const checkedArg = getTypeOrValueForNode(arg, ctx, {
|
|
3610
|
+
kind: "argument",
|
|
3611
|
+
constraint: param.type,
|
|
3612
|
+
});
|
|
3613
|
+
if (!checkedArg) {
|
|
3614
|
+
satisfied = false;
|
|
3615
|
+
continue;
|
|
3616
|
+
}
|
|
3617
|
+
const resolved = collector.pipe(checkEntityAssignableToConstraint(checkedArg, param.type, arg));
|
|
3618
|
+
satisfied &&= !!resolved;
|
|
3619
|
+
resolvedArgs.push(resolved
|
|
3620
|
+
? isValue(resolved)
|
|
3621
|
+
? marshalTypeForJs(resolved, undefined)
|
|
3622
|
+
: resolved
|
|
3623
|
+
: undefined);
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
reportCheckerDiagnostics(collector.diagnostics);
|
|
3627
|
+
return [satisfied, resolvedArgs];
|
|
3628
|
+
}
|
|
3629
|
+
function checkFunctionReturn(target, result, diagnosticTarget) {
|
|
3630
|
+
const [checked, diagnostics] = checkEntityAssignableToConstraint(result, target.returnType, diagnosticTarget);
|
|
3631
|
+
if (diagnostics.length > 0) {
|
|
3632
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3633
|
+
code: "function-return",
|
|
3634
|
+
messageId: "unassignable",
|
|
3635
|
+
format: {
|
|
3636
|
+
name: getEntityName(target, { printable: true }),
|
|
3637
|
+
entityKind: result.entityKind.toLowerCase(),
|
|
3638
|
+
return: getEntityName(result, { printable: true }),
|
|
3639
|
+
type: getEntityName(target.returnType, { printable: true }),
|
|
3640
|
+
},
|
|
3641
|
+
target: diagnosticTarget,
|
|
3642
|
+
}));
|
|
3643
|
+
}
|
|
3644
|
+
return checked;
|
|
3645
|
+
}
|
|
3646
|
+
function checkEntityAssignableToConstraint(entity, constraint, diagnosticTarget) {
|
|
3647
|
+
const constraintIsValue = !!constraint.valueType;
|
|
3648
|
+
const constraintIsType = !!constraint.type;
|
|
3649
|
+
const collector = createDiagnosticCollector();
|
|
3650
|
+
switch (true) {
|
|
3651
|
+
case constraintIsValue && constraintIsType: {
|
|
3652
|
+
const tried = tryAssignValue();
|
|
3653
|
+
if (tried[0] !== null || entity.entityKind === "Value") {
|
|
3654
|
+
// Succeeded as value or is a value
|
|
3655
|
+
return tried;
|
|
3656
|
+
}
|
|
3657
|
+
// Now we are guaranteed a type.
|
|
3658
|
+
const typeEntity = entity.entityKind === "Indeterminate" ? entity.type : entity;
|
|
3659
|
+
const assignable = collector.pipe(relation.isTypeAssignableTo(typeEntity, constraint.type, diagnosticTarget));
|
|
3660
|
+
return collector.wrap(assignable ? typeEntity : null);
|
|
3661
|
+
}
|
|
3662
|
+
case constraintIsValue: {
|
|
3663
|
+
const normed = collector.pipe(normalizeValue(entity, constraint, diagnosticTarget));
|
|
3664
|
+
// Error should have been reported in normalizeValue
|
|
3665
|
+
if (!normed)
|
|
3666
|
+
return collector.wrap(null);
|
|
3667
|
+
const assignable = collector.pipe(relation.isValueOfType(normed, constraint.valueType, diagnosticTarget));
|
|
3668
|
+
return collector.wrap(assignable ? normed : null);
|
|
3669
|
+
}
|
|
3670
|
+
case constraintIsType: {
|
|
3671
|
+
if (entity.entityKind === "Indeterminate")
|
|
3672
|
+
entity = entity.type;
|
|
3673
|
+
if (entity.entityKind !== "Type") {
|
|
3674
|
+
collector.add(createDiagnostic({
|
|
3675
|
+
code: "value-in-type",
|
|
3676
|
+
format: { name: getTypeName(entity.type) },
|
|
3677
|
+
target: diagnosticTarget,
|
|
3678
|
+
}));
|
|
3679
|
+
return collector.wrap(null);
|
|
3680
|
+
}
|
|
3681
|
+
const assignable = collector.pipe(relation.isTypeAssignableTo(entity, constraint.type, diagnosticTarget));
|
|
3682
|
+
return collector.wrap(assignable ? entity : null);
|
|
3683
|
+
}
|
|
3684
|
+
default: {
|
|
3685
|
+
compilerAssert(false, "Expected at least one of type or value constraint to be defined.");
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
function tryAssignValue() {
|
|
3689
|
+
const collector = createDiagnosticCollector();
|
|
3690
|
+
const normed = collector.pipe(normalizeValue(entity, constraint, diagnosticTarget));
|
|
3691
|
+
const assignable = normed
|
|
3692
|
+
? collector.pipe(relation.isValueOfType(normed, constraint.valueType, diagnosticTarget))
|
|
3693
|
+
: false;
|
|
3694
|
+
return collector.wrap(assignable ? normed : null);
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
function normalizeValue(entity, constraint, diagnosticTarget) {
|
|
3698
|
+
if (entity.entityKind === "Value")
|
|
3699
|
+
return [entity, []];
|
|
3700
|
+
if (entity.entityKind === "Indeterminate") {
|
|
3701
|
+
// Coerce to a value
|
|
3702
|
+
const coerced = getValueFromIndeterminate(entity.type, constraint.type && { kind: "argument", type: constraint.type }, entity.type.node);
|
|
3703
|
+
if (coerced?.entityKind !== "Value") {
|
|
3704
|
+
return [
|
|
3705
|
+
null,
|
|
3706
|
+
[
|
|
3707
|
+
createDiagnostic({
|
|
3708
|
+
code: "expect-value",
|
|
3709
|
+
format: { name: getTypeName(entity.type) },
|
|
3710
|
+
target: diagnosticTarget,
|
|
3711
|
+
}),
|
|
3712
|
+
],
|
|
3713
|
+
];
|
|
3714
|
+
}
|
|
3715
|
+
return [coerced, []];
|
|
3716
|
+
}
|
|
3717
|
+
if (entity.entityKind === "Type") {
|
|
3718
|
+
return [
|
|
3719
|
+
null,
|
|
3720
|
+
[
|
|
3721
|
+
createDiagnostic({
|
|
3722
|
+
code: "expect-value",
|
|
3723
|
+
format: { name: getTypeName(entity) },
|
|
3724
|
+
target: diagnosticTarget,
|
|
3725
|
+
}),
|
|
3726
|
+
],
|
|
3727
|
+
];
|
|
3728
|
+
}
|
|
3729
|
+
compilerAssert(false, `Unreachable: unexpected entity kind '${entity.entityKind}'`);
|
|
3730
|
+
}
|
|
3268
3731
|
function checkTypeOfExpression(ctx, node) {
|
|
3269
3732
|
const entity = checkNode(ctx, node.target, undefined);
|
|
3270
3733
|
if (entity === null) {
|
|
@@ -3646,7 +4109,7 @@ export function createChecker(program, resolver) {
|
|
|
3646
4109
|
// if the prop type is an error we don't need to validate again.
|
|
3647
4110
|
return null;
|
|
3648
4111
|
}
|
|
3649
|
-
const defaultValue = getValueForNode(defaultNode, ctx
|
|
4112
|
+
const defaultValue = getValueForNode(defaultNode, ctx, {
|
|
3650
4113
|
kind: "assignment",
|
|
3651
4114
|
type,
|
|
3652
4115
|
});
|
|
@@ -3772,20 +4235,23 @@ export function createChecker(program, resolver) {
|
|
|
3772
4235
|
}
|
|
3773
4236
|
const resolvedArgs = [];
|
|
3774
4237
|
function resolveArg(argNode, perParamType) {
|
|
3775
|
-
const arg = getTypeOrValueForNode(argNode, ctx
|
|
4238
|
+
const arg = getTypeOrValueForNode(argNode, ctx, {
|
|
3776
4239
|
kind: "argument",
|
|
3777
4240
|
constraint: perParamType,
|
|
3778
4241
|
});
|
|
3779
4242
|
if (arg !== null &&
|
|
3780
4243
|
!(isType(arg) && isErrorType(arg)) &&
|
|
3781
4244
|
checkArgumentAssignable(arg, perParamType, argNode)) {
|
|
4245
|
+
const [valid, jsValue] = resolveArgumentJsValue(arg, extractValueOfConstraints({
|
|
4246
|
+
kind: "argument",
|
|
4247
|
+
constraint: perParamType,
|
|
4248
|
+
}), argNode);
|
|
4249
|
+
if (!valid)
|
|
4250
|
+
return undefined;
|
|
3782
4251
|
return {
|
|
3783
4252
|
value: arg,
|
|
3784
4253
|
node: argNode,
|
|
3785
|
-
jsValue
|
|
3786
|
-
kind: "argument",
|
|
3787
|
-
constraint: perParamType,
|
|
3788
|
-
})),
|
|
4254
|
+
jsValue,
|
|
3789
4255
|
};
|
|
3790
4256
|
}
|
|
3791
4257
|
else {
|
|
@@ -3853,16 +4319,17 @@ export function createChecker(program, resolver) {
|
|
|
3853
4319
|
function getIndexType(type) {
|
|
3854
4320
|
return type.kind === "Model" ? type.indexer?.value : undefined;
|
|
3855
4321
|
}
|
|
3856
|
-
function
|
|
4322
|
+
function resolveArgumentJsValue(value, valueConstraint, diagnosticTarget) {
|
|
3857
4323
|
if (valueConstraint !== undefined) {
|
|
3858
4324
|
if (isValue(value)) {
|
|
3859
|
-
|
|
4325
|
+
const unmarshaled = marshalTypeForJs(value, valueConstraint.type);
|
|
4326
|
+
return [true, unmarshaled];
|
|
3860
4327
|
}
|
|
3861
4328
|
else {
|
|
3862
|
-
return value;
|
|
4329
|
+
return [true, value];
|
|
3863
4330
|
}
|
|
3864
4331
|
}
|
|
3865
|
-
return value;
|
|
4332
|
+
return [true, value];
|
|
3866
4333
|
}
|
|
3867
4334
|
function checkArgumentAssignable(argumentType, parameterType, diagnosticTarget) {
|
|
3868
4335
|
const [valid] = relation.isTypeAssignableTo(argumentType, parameterType, diagnosticTarget);
|
|
@@ -3986,6 +4453,9 @@ export function createChecker(program, resolver) {
|
|
|
3986
4453
|
// we're not instantiating this model and we've already checked it
|
|
3987
4454
|
return links.declaredType;
|
|
3988
4455
|
}
|
|
4456
|
+
if (ctx.mapper === undefined) {
|
|
4457
|
+
checkModifiers(program, node);
|
|
4458
|
+
}
|
|
3989
4459
|
checkTemplateDeclaration(ctx, node);
|
|
3990
4460
|
const decorators = [];
|
|
3991
4461
|
const type = createType({
|
|
@@ -4097,6 +4567,9 @@ export function createChecker(program, resolver) {
|
|
|
4097
4567
|
if (links.declaredType && ctx.mapper === undefined) {
|
|
4098
4568
|
return links.declaredType;
|
|
4099
4569
|
}
|
|
4570
|
+
if (ctx.mapper === undefined) {
|
|
4571
|
+
checkModifiers(program, node);
|
|
4572
|
+
}
|
|
4100
4573
|
checkTemplateDeclaration(ctx, node);
|
|
4101
4574
|
const aliasSymId = getNodeSym(node);
|
|
4102
4575
|
if (pendingResolutions.has(aliasSymId, ResolutionKind.Type)) {
|
|
@@ -4130,6 +4603,7 @@ export function createChecker(program, resolver) {
|
|
|
4130
4603
|
if (links.value !== undefined) {
|
|
4131
4604
|
return links.value;
|
|
4132
4605
|
}
|
|
4606
|
+
checkModifiers(program, node);
|
|
4133
4607
|
const type = node.type ? getTypeForNode(node.type, undefined) : undefined;
|
|
4134
4608
|
if (pendingResolutions.has(node.symbol, ResolutionKind.Value)) {
|
|
4135
4609
|
reportCheckerDiagnostic(createDiagnostic({
|
|
@@ -4164,12 +4638,14 @@ export function createChecker(program, resolver) {
|
|
|
4164
4638
|
case "EnumValue":
|
|
4165
4639
|
case "NullValue":
|
|
4166
4640
|
case "ScalarValue":
|
|
4641
|
+
case "Function":
|
|
4167
4642
|
return value;
|
|
4168
4643
|
}
|
|
4169
4644
|
}
|
|
4170
4645
|
function checkEnum(ctx, node) {
|
|
4171
4646
|
const links = getSymbolLinks(node.symbol);
|
|
4172
4647
|
if (!links.type) {
|
|
4648
|
+
checkModifiers(program, node);
|
|
4173
4649
|
const enumType = (links.type = createType({
|
|
4174
4650
|
kind: "Enum",
|
|
4175
4651
|
name: node.id.sv,
|
|
@@ -4219,6 +4695,9 @@ export function createChecker(program, resolver) {
|
|
|
4219
4695
|
// we're not instantiating this interface and we've already checked it
|
|
4220
4696
|
return links.declaredType;
|
|
4221
4697
|
}
|
|
4698
|
+
if (ctx.mapper === undefined) {
|
|
4699
|
+
checkModifiers(program, node);
|
|
4700
|
+
}
|
|
4222
4701
|
checkTemplateDeclaration(ctx, node);
|
|
4223
4702
|
const interfaceType = createType({
|
|
4224
4703
|
kind: "Interface",
|
|
@@ -4305,6 +4784,9 @@ export function createChecker(program, resolver) {
|
|
|
4305
4784
|
// we're not instantiating this union and we've already checked it
|
|
4306
4785
|
return links.declaredType;
|
|
4307
4786
|
}
|
|
4787
|
+
if (ctx.mapper === undefined) {
|
|
4788
|
+
checkModifiers(program, node);
|
|
4789
|
+
}
|
|
4308
4790
|
checkTemplateDeclaration(ctx, node);
|
|
4309
4791
|
const variants = createRekeyableMap();
|
|
4310
4792
|
const unionType = createType({
|
|
@@ -5134,25 +5616,70 @@ function applyDecoratorToType(program, decApp, target) {
|
|
|
5134
5616
|
}
|
|
5135
5617
|
}
|
|
5136
5618
|
}
|
|
5137
|
-
function
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5619
|
+
function createPassThruContexts(program, target) {
|
|
5620
|
+
const decCtx = {
|
|
5621
|
+
program,
|
|
5622
|
+
decoratorTarget: target,
|
|
5623
|
+
getArgumentTarget: () => target,
|
|
5624
|
+
call: (decorator, target, ...args) => {
|
|
5625
|
+
return decCtx.callDecorator(decorator, target, ...args);
|
|
5626
|
+
},
|
|
5627
|
+
callDecorator(decorator, target, ...args) {
|
|
5628
|
+
return decorator(decCtx, target, ...args);
|
|
5629
|
+
},
|
|
5630
|
+
callFunction(fn, ...args) {
|
|
5631
|
+
return fn(fnCtx, ...args);
|
|
5632
|
+
},
|
|
5633
|
+
};
|
|
5634
|
+
const fnCtx = {
|
|
5635
|
+
program,
|
|
5636
|
+
functionCallTarget: target,
|
|
5637
|
+
getArgumentTarget: () => target,
|
|
5638
|
+
callFunction(fn, ...args) {
|
|
5639
|
+
return fn(fnCtx, ...args);
|
|
5640
|
+
},
|
|
5641
|
+
callDecorator(decorator, target, ...args) {
|
|
5642
|
+
return decorator(decCtx, target, ...args);
|
|
5643
|
+
},
|
|
5644
|
+
};
|
|
5148
5645
|
return {
|
|
5646
|
+
decorator: decCtx,
|
|
5647
|
+
function: fnCtx,
|
|
5648
|
+
};
|
|
5649
|
+
}
|
|
5650
|
+
function createDecoratorContext(program, decApp) {
|
|
5651
|
+
const passthrough = createPassThruContexts(program, decApp.node);
|
|
5652
|
+
const decCtx = {
|
|
5149
5653
|
program,
|
|
5150
5654
|
decoratorTarget: decApp.node,
|
|
5151
5655
|
getArgumentTarget: (index) => {
|
|
5152
5656
|
return decApp.args[index]?.node;
|
|
5153
5657
|
},
|
|
5154
5658
|
call: (decorator, target, ...args) => {
|
|
5155
|
-
return decorator
|
|
5659
|
+
return decCtx.callDecorator(decorator, target, ...args);
|
|
5660
|
+
},
|
|
5661
|
+
callDecorator: (decorator, target, ...args) => {
|
|
5662
|
+
return decorator(passthrough.decorator, target, ...args);
|
|
5663
|
+
},
|
|
5664
|
+
callFunction(fn, ...args) {
|
|
5665
|
+
return fn(passthrough.function, ...args);
|
|
5666
|
+
},
|
|
5667
|
+
};
|
|
5668
|
+
return decCtx;
|
|
5669
|
+
}
|
|
5670
|
+
function createFunctionContext(program, fnCall) {
|
|
5671
|
+
const passthrough = createPassThruContexts(program, fnCall);
|
|
5672
|
+
return {
|
|
5673
|
+
program,
|
|
5674
|
+
functionCallTarget: fnCall,
|
|
5675
|
+
getArgumentTarget: (index) => {
|
|
5676
|
+
return fnCall.arguments[index];
|
|
5677
|
+
},
|
|
5678
|
+
callDecorator(decorator, target, ...args) {
|
|
5679
|
+
return decorator(passthrough.decorator, target, ...args);
|
|
5680
|
+
},
|
|
5681
|
+
callFunction(fn, ...args) {
|
|
5682
|
+
return fn(passthrough.function, ...args);
|
|
5156
5683
|
},
|
|
5157
5684
|
};
|
|
5158
5685
|
}
|