Skip to content

Commit

Permalink
Fix: Using a scalar constructor defined in a parent scalar doesn't re…
Browse files Browse the repository at this point in the history
…ference the right scalar (#3573)

```
const a = unixTimestamp.fromISO("...");
```

a would have the scalar utcDateTime not unixTimestamp
  • Loading branch information
timotheeguerin authored Jun 12, 2024
1 parent 35e8625 commit 5bc98d9
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: internal
packages:
- "@typespec/compiler"
---

Fix: Using a scalar constructor defined in a parent scalar doesn't reference the right scalar
15 changes: 14 additions & 1 deletion packages/compiler/src/core/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5621,7 +5621,6 @@ export function createChecker(program: Program): Checker {
decorators,
derivedScalars: [],
});
checkScalarConstructors(type, node, type.constructors, mapper);
linkType(links, type, mapper);

if (node.extends) {
Expand All @@ -5631,6 +5630,7 @@ export function createChecker(program: Program): Checker {
type.baseScalar.derivedScalars.push(type);
}
}
checkScalarConstructors(type, node, type.constructors, mapper);
decorators.push(...checkDecorators(type, node, mapper));

if (mapper === undefined) {
Expand Down Expand Up @@ -5695,6 +5695,19 @@ export function createChecker(program: Program): Checker {
constructors: Map<string, ScalarConstructor>,
mapper: TypeMapper | undefined
) {
if (parentScalar.baseScalar) {
for (const member of parentScalar.baseScalar.constructors.values()) {
const newConstructor: ScalarConstructor = cloneTypeForSymbol(
getMemberSymbol(node.symbol, member.name)!,
{
...member,
scalar: parentScalar,
}
);
linkIndirectMember(node, newConstructor, mapper);
constructors.set(member.name, newConstructor);
}
}
for (const member of node.members) {
const constructor = checkScalarConstructor(member, mapper, parentScalar);
if (constructors.has(constructor.name as string)) {
Expand Down
5 changes: 3 additions & 2 deletions packages/compiler/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,8 @@ export type MemberContainerNode =
| ModelExpressionNode
| InterfaceStatementNode
| EnumStatementNode
| UnionStatementNode;
| UnionStatementNode
| ScalarStatementNode;

export type MemberNode =
| ModelPropertyNode
Expand All @@ -1141,7 +1142,7 @@ export type MemberContainerType = Model | Enum | Interface | Union | Scalar;
/**
* Type that can be used as members of a container type.
*/
export type MemberType = ModelProperty | EnumMember | Operation | UnionVariant;
export type MemberType = ModelProperty | EnumMember | Operation | UnionVariant | ScalarConstructor;

export type Comment = LineComment | BlockComment;

Expand Down
15 changes: 15 additions & 0 deletions packages/compiler/test/checker/values/scalar-values.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ describe("instantiate with named constructor", () => {
]);
});

it("instantiate using constructor from parent scalar", async () => {
const value = await compileValue(
`b.fromString("a")`,
`
scalar a { init fromString(val: string);}
scalar b extends a { }
`
);
strictEqual(value.valueKind, "ScalarValue");
strictEqual(value.type.kind, "Scalar");
strictEqual(value.type.name, "b");
strictEqual(value.scalar?.name, "b");
strictEqual(value.value.name, "fromString");
});

it("instantiate from another scalar", async () => {
const value = await compileValue(
`b.fromA(a.fromString("a"))`,
Expand Down

0 comments on commit 5bc98d9

Please sign in to comment.