Skip to content

Commit 52374aa

Browse files
authored
feat: error if type parameter is used in nested named type declaration (#750)
Closes #748 ### Summary of Changes Show an error if a type parameter of a class is used inside a nested named type declaration.
1 parent 6510555 commit 52374aa

File tree

5 files changed

+69
-5
lines changed

5 files changed

+69
-5
lines changed

docs/language/common/types.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ A declaration with an _enum type_ must be one of the [variants][variants] of the
4040

4141
```sds
4242
enum SomeEnum {
43-
SomeEnumVariant,
43+
SomeEnumVariant
4444
SomeOtherEnumVariant(count: Int)
4545
}
4646
```

packages/safe-ds-lang/src/language/validation/other/declarations/typeParameters.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
import { findLocalReferences, getContainerOfType, hasContainerOfType, ValidationAcceptor } from 'langium';
12
import {
23
isSdsCallable,
34
isSdsClass,
5+
isSdsDeclaration,
6+
isSdsNamedTypeDeclaration,
47
isSdsParameterList,
58
isSdsUnionType,
69
SdsTypeParameter,
710
} from '../../../generated/ast.js';
8-
import { findLocalReferences, getContainerOfType, hasContainerOfType, ValidationAcceptor } from 'langium';
911

1012
export const CODE_TYPE_PARAMETER_INSUFFICIENT_CONTEXT = 'type-parameter/insufficient-context';
13+
export const CODE_TYPE_PARAMETER_USAGE = 'type-parameter/usage';
1114

1215
export const typeParameterMustHaveSufficientContext = (node: SdsTypeParameter, accept: ValidationAcceptor) => {
1316
const containingCallable = getContainerOfType(node, isSdsCallable);
@@ -45,3 +48,29 @@ export const typeParameterMustHaveSufficientContext = (node: SdsTypeParameter, a
4548
});
4649
}
4750
};
51+
52+
export const typeParameterMustNotBeUsedInNestedNamedTypeDeclarations = (
53+
node: SdsTypeParameter,
54+
accept: ValidationAcceptor,
55+
) => {
56+
// Only classes can have nested named type declarations
57+
const declarationWithTypeParameter = getContainerOfType(node.$container, isSdsDeclaration);
58+
if (!isSdsClass(declarationWithTypeParameter)) {
59+
return;
60+
}
61+
62+
findLocalReferences(node).forEach((it) => {
63+
const reference = it.$refNode?.astNode;
64+
const containingNamedTypeDeclaration = getContainerOfType(reference, isSdsNamedTypeDeclaration);
65+
if (
66+
reference &&
67+
containingNamedTypeDeclaration &&
68+
containingNamedTypeDeclaration !== declarationWithTypeParameter
69+
) {
70+
accept('error', 'Type parameters cannot be used in nested named type declarations.', {
71+
node: reference,
72+
code: CODE_TYPE_PARAMETER_USAGE,
73+
});
74+
}
75+
});
76+
};

packages/safe-ds-lang/src/language/validation/safe-ds-validator.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ import {
7272
segmentShouldBeUsed,
7373
} from './other/declarations/segments.js';
7474
import { typeParameterConstraintLeftOperandMustBeOwnTypeParameter } from './other/declarations/typeParameterConstraints.js';
75-
import { typeParameterMustHaveSufficientContext } from './other/declarations/typeParameters.js';
75+
import {
76+
typeParameterMustHaveSufficientContext,
77+
typeParameterMustNotBeUsedInNestedNamedTypeDeclarations,
78+
} from './other/declarations/typeParameters.js';
7679
import { callArgumentsMustBeConstantIfParameterIsConstant } from './other/expressions/calls.js';
7780
import { divisionDivisorMustNotBeZero } from './other/expressions/infixOperations.js';
7881
import {
@@ -309,7 +312,10 @@ export const registerValidationChecks = function (services: SafeDsServices) {
309312
segmentShouldBeUsed(services),
310313
],
311314
SdsTemplateString: [templateStringMustHaveExpressionBetweenTwoStringParts],
312-
SdsTypeParameter: [typeParameterMustHaveSufficientContext],
315+
SdsTypeParameter: [
316+
typeParameterMustHaveSufficientContext,
317+
typeParameterMustNotBeUsedInNestedNamedTypeDeclarations,
318+
],
313319
SdsTypeParameterConstraint: [typeParameterConstraintLeftOperandMustBeOwnTypeParameter],
314320
SdsTypeParameterList: [typeParameterListShouldNotBeEmpty],
315321
SdsUnionType: [
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tests.validation.other.declarations.typeParameterConstraints.typeParameterOnContainer
1+
package tests.validation.other.declarations.constraints.typeParameterConstraints.typeParameterOnContainer
22

33
annotation MyAnnotation where {
44
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package tests.validation.other.declarations.typeParameters.usage
2+
3+
// $TEST$ no error "Type parameters cannot be used in nested named type declarations."
4+
class MyClass<T>(p: »T«) {
5+
// $TEST$ no error "Type parameters cannot be used in nested named type declarations."
6+
attr a: »T«
7+
8+
// $TEST$ no error "Type parameters cannot be used in nested named type declarations."
9+
// $TEST$ no error "Type parameters cannot be used in nested named type declarations."
10+
// $TEST$ no error "Type parameters cannot be used in nested named type declarations."
11+
// $TEST$ no error "Type parameters cannot be used in nested named type declarations."
12+
fun f<S>(p1: »T«, p2: »S«) -> (r1: »T«, r2: »S«)
13+
14+
// $TEST$ error "Type parameters cannot be used in nested named type declarations."
15+
// $TEST$ no error "Type parameters cannot be used in nested named type declarations."
16+
class MyInnerClass<S>(p1: »T«, p2: »S«) {
17+
// $TEST$ error "Type parameters cannot be used in nested named type declarations."
18+
attr a: »T«
19+
20+
// $TEST$ error "Type parameters cannot be used in nested named type declarations."
21+
fun f(p: »T«)
22+
}
23+
24+
enum MyInnerEnum {
25+
// $TEST$ error "Type parameters cannot be used in nested named type declarations."
26+
// $TEST$ no error "Type parameters cannot be used in nested named type declarations."
27+
MyEnumVariant<S>(p1: »T«, p2: »S«)
28+
}
29+
}

0 commit comments

Comments
 (0)