Skip to content

Commit 1775705

Browse files
feat: various features related to literal types (#657)
Closes partially #80 ### Summary of Changes * Show an error if literal types have no literals * Show an error if lists or maps are used in a literal types * Mark literal types as experimental (show a warning when they are used) * Compute type of manifest literal types * Evaluate literals to a literal type instead of the corresponding class. For example, the literal `1` now gets the type `literal<1>` instead of `Int`). --------- Co-authored-by: megalinter-bot <[email protected]>
1 parent ca47870 commit 1775705

File tree

47 files changed

+692
-171
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+692
-171
lines changed

src/language/safe-ds-module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import { SafeDsAnnotations } from './builtins/safe-ds-annotations.js';
2424
import { SafeDsClassHierarchy } from './typing/safe-ds-class-hierarchy.js';
2525
import { SafeDsPartialEvaluator } from './partialEvaluation/safe-ds-partial-evaluator.js';
2626
import { SafeDsSemanticTokenProvider } from './lsp/safe-ds-semantic-token-provider.js';
27+
import { SafeDsTypeChecker } from './typing/safe-ds-type-checker.js';
28+
import { SafeDsCoreTypes } from './typing/safe-ds-core-types.js';
2729

2830
/**
2931
* Declaration of custom services - add your own service classes here.
@@ -41,6 +43,8 @@ export type SafeDsAddedServices = {
4143
};
4244
types: {
4345
ClassHierarchy: SafeDsClassHierarchy;
46+
CoreTypes: SafeDsCoreTypes;
47+
TypeChecker: SafeDsTypeChecker;
4448
TypeComputer: SafeDsTypeComputer;
4549
};
4650
workspace: {
@@ -83,6 +87,8 @@ export const SafeDsModule: Module<SafeDsServices, PartialLangiumServices & SafeD
8387
},
8488
types: {
8589
ClassHierarchy: (services) => new SafeDsClassHierarchy(services),
90+
CoreTypes: (services) => new SafeDsCoreTypes(services),
91+
TypeChecker: (services) => new SafeDsTypeChecker(services),
8692
TypeComputer: (services) => new SafeDsTypeComputer(services),
8793
},
8894
workspace: {

src/language/typing/model.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import {
2-
isSdsNull,
32
SdsAbstractResult,
43
SdsCallable,
54
SdsClass,
65
SdsDeclaration,
76
SdsEnum,
87
SdsEnumVariant,
9-
SdsLiteral,
108
SdsParameter,
119
} from '../generated/ast.js';
10+
import { Constant, NullConstant } from '../partialEvaluation/model.js';
1211

1312
/* c8 ignore start */
1413
export abstract class Type {
@@ -68,10 +67,10 @@ export class CallableType extends Type {
6867
export class LiteralType extends Type {
6968
override readonly isNullable: boolean;
7069

71-
constructor(readonly values: SdsLiteral[]) {
70+
constructor(readonly constants: Constant[]) {
7271
super();
7372

74-
this.isNullable = values.some(isSdsNull);
73+
this.isNullable = constants.some((it) => it === NullConstant);
7574
}
7675

7776
override copyWithNullability(isNullable: boolean): LiteralType {
@@ -93,11 +92,15 @@ export class LiteralType extends Type {
9392
return false;
9493
}
9594

96-
throw Error('Not implemented');
95+
if (other.constants.length !== this.constants.length) {
96+
return false;
97+
}
98+
99+
return other.constants.every((otherValue) => this.constants.some((value) => value.equals(otherValue)));
97100
}
98101

99102
override toString(): string {
100-
throw Error('Not implemented');
103+
return `literal<${this.constants.join(', ')}>`;
101104
}
102105
}
103106

@@ -300,10 +303,12 @@ export class StaticType extends Type {
300303
}
301304

302305
export class UnionType extends Type {
303-
override readonly isNullable = false;
306+
override readonly isNullable: boolean;
304307

305308
constructor(readonly possibleTypes: Type[]) {
306309
super();
310+
311+
this.isNullable = possibleTypes.some((it) => it.isNullable);
307312
}
308313

309314
override copyWithNullability(_isNullable: boolean): UnionType {

src/language/typing/safe-ds-class-hierarchy.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,26 @@ export class SafeDsClassHierarchy {
1616
}
1717

1818
/**
19-
* Returns a stream of all superclasses of the given class. The class itself is not included in the stream unless
20-
* there is a cycle in the inheritance hierarchy. Direct ancestors are returned first, followed by their ancestors
21-
* and so on.
19+
* Returns `true` if the given node is equal to or a subclass of the given other node. If one of the nodes is
20+
* undefined, `false` is returned.
21+
*/
22+
isEqualToOrSubclassOf(node: SdsClass | undefined, other: SdsClass | undefined): boolean {
23+
if (!node || !other) {
24+
return false;
25+
}
26+
27+
// Nothing is a subclass of everything
28+
if (node === this.builtinClasses.Nothing) {
29+
return true;
30+
}
31+
32+
return node === other || this.streamSuperclasses(node).includes(other);
33+
}
34+
35+
/**
36+
* Returns a stream of all superclasses of the given class. Direct ancestors are returned first, followed by their
37+
* ancestors and so on. The class itself is not included in the stream unless there is a cycle in the inheritance
38+
* hierarchy.
2239
*/
2340
streamSuperclasses(node: SdsClass | undefined): Stream<SdsClass> {
2441
if (!node) {
@@ -58,3 +75,22 @@ export class SafeDsClassHierarchy {
5875
return undefined;
5976
}
6077
}
78+
79+
// fun SdsClass.superClassMembers() =
80+
// this.superClasses().flatMap { it.classMembersOrEmpty().asSequence() }
81+
//
82+
// // TODO only static methods can be hidden
83+
// fun SdsFunction.hiddenFunction(): SdsFunction? {
84+
// val containingClassOrInterface = closestAncestorOrNull<SdsClass>() ?: return null
85+
// return containingClassOrInterface.superClassMembers()
86+
// .filterIsInstance<SdsFunction>()
87+
// .firstOrNull { it.name == name }
88+
// }
89+
//
90+
// fun SdsClass?.inheritedNonStaticMembersOrEmpty(): Set<SdsAbstractDeclaration> {
91+
// return this?.parentClassesOrEmpty()
92+
// ?.flatMap { it.classMembersOrEmpty() }
93+
// ?.filter { it is SdsAttribute && !it.isStatic || it is SdsFunction && !it.isStatic }
94+
// ?.toSet()
95+
// .orEmpty()
96+
// }
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { WorkspaceCache } from 'langium';
2+
import { SafeDsServices } from '../safe-ds-module.js';
3+
import { SafeDsClasses } from '../builtins/safe-ds-classes.js';
4+
import { ClassType, Type, UnknownType } from './model.js';
5+
import { SdsClass } from '../generated/ast.js';
6+
7+
export class SafeDsCoreTypes {
8+
private readonly builtinClasses: SafeDsClasses;
9+
private readonly cache: WorkspaceCache<string, Type>;
10+
11+
constructor(services: SafeDsServices) {
12+
this.builtinClasses = services.builtins.Classes;
13+
this.cache = new WorkspaceCache(services.shared);
14+
}
15+
16+
get AnyOrNull(): Type {
17+
return this.createCoreType(this.builtinClasses.Any, true);
18+
}
19+
20+
get Boolean(): Type {
21+
return this.createCoreType(this.builtinClasses.Boolean);
22+
}
23+
24+
get Float(): Type {
25+
return this.createCoreType(this.builtinClasses.Float);
26+
}
27+
28+
get Int(): Type {
29+
return this.createCoreType(this.builtinClasses.Int);
30+
}
31+
32+
get List(): Type {
33+
return this.createCoreType(this.builtinClasses.List);
34+
}
35+
36+
get Map(): Type {
37+
return this.createCoreType(this.builtinClasses.Map);
38+
}
39+
40+
/* c8 ignore start */
41+
get NothingOrNull(): Type {
42+
return this.createCoreType(this.builtinClasses.Nothing, true);
43+
}
44+
/* c8 ignore stop */
45+
46+
get String(): Type {
47+
return this.createCoreType(this.builtinClasses.String);
48+
}
49+
50+
private createCoreType(coreClass: SdsClass | undefined, isNullable: boolean = false): Type {
51+
/* c8 ignore start */
52+
if (!coreClass) {
53+
return UnknownType;
54+
}
55+
/* c8 ignore stop */
56+
57+
const key = `${coreClass.name}~${isNullable}`;
58+
return this.cache.get(key, () => new ClassType(coreClass, isNullable));
59+
}
60+
}

0 commit comments

Comments
 (0)