Skip to content

Commit cba3abf

Browse files
feat: error if left operand of type parameter constraint does not belong to declaration with constraint (#571)
Closes #562 ### Summary of Changes Show an error if the left operand of a type parameter constraint refers to a type parameter that does not belong to the declaration with the constraint (but a declaration that contains it). --------- Co-authored-by: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com>
1 parent f6ffa4d commit cba3abf

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { isSdsDeclaration, SdsTypeParameterConstraint } from '../../../generated/ast.js';
2+
import { getContainerOfType, ValidationAcceptor } from 'langium';
3+
4+
export const CODE_TYPE_PARAMETER_CONSTRAINT_LEFT_OPERAND = 'type-parameter-constraint/left-operand';
5+
6+
export const typeParameterConstraintLeftOperandMustBeOwnTypeParameter = (
7+
node: SdsTypeParameterConstraint,
8+
accept: ValidationAcceptor,
9+
) => {
10+
const typeParameter = node.leftOperand.ref;
11+
if (!typeParameter) {
12+
return;
13+
}
14+
15+
const declarationWithConstraint = getContainerOfType(node.$container, isSdsDeclaration);
16+
const declarationWithTypeParameters = getContainerOfType(typeParameter.$container, isSdsDeclaration);
17+
18+
if (declarationWithConstraint !== declarationWithTypeParameters) {
19+
accept('error', 'The left operand must refer to a type parameter of the declaration with the constraint.', {
20+
node,
21+
property: 'leftOperand',
22+
code: CODE_TYPE_PARAMETER_CONSTRAINT_LEFT_OPERAND,
23+
});
24+
}
25+
};

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

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { templateStringMustHaveExpressionBetweenTwoStringParts } from './other/e
1919
import { yieldMustNotBeUsedInPipeline } from './other/statements/assignments.js';
2020
import { attributeMustHaveTypeHint, parameterMustHaveTypeHint, resultMustHaveTypeHint } from './types.js';
2121
import { moduleDeclarationsMustMatchFileKind, moduleWithDeclarationsMustStatePackage } from './other/modules.js';
22+
import { typeParameterConstraintLeftOperandMustBeOwnTypeParameter } from './other/declarations/typeParameterConstraints.js';
2223

2324
/**
2425
* Register custom validation checks.
@@ -40,6 +41,7 @@ export const registerValidationChecks = function (services: SafeDsServices) {
4041
SdsResult: [resultMustHaveTypeHint],
4142
SdsSegment: [segmentResultListShouldNotBeEmpty],
4243
SdsTemplateString: [templateStringMustHaveExpressionBetweenTwoStringParts],
44+
SdsTypeParameterConstraint: [typeParameterConstraintLeftOperandMustBeOwnTypeParameter],
4345
SdsUnionType: [unionTypeShouldNotHaveASingularTypeArgument],
4446
SdsYield: [yieldMustNotBeUsedInPipeline],
4547
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package tests.validation.other.declarations.typeParameterConstraints.typeParameterOnContainer
2+
3+
annotation MyAnnotation where {
4+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
5+
»Unresolved« sub MyGlobalClass,
6+
}
7+
8+
class MyGlobalClass<T1> where {
9+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
10+
»T1« sub MyGlobalClass,
11+
12+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
13+
»Unresolved« sub MyGlobalClass
14+
} {
15+
class MyNestedClass<T2> where {
16+
// $TEST$ error "The left operand must refer to a type parameter of the declaration with the constraint."
17+
»T1« sub MyGlobalClass,
18+
19+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
20+
»T2« sub MyGlobalClass,
21+
22+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
23+
»Unresolved« sub MyGlobalClass,
24+
}
25+
26+
enum MyNestedEnum {
27+
MyEnumVariant<T2> where {
28+
// $TEST$ error "The left operand must refer to a type parameter of the declaration with the constraint."
29+
»T1« sub MyGlobalClass,
30+
31+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
32+
»T2« sub MyGlobalClass,
33+
34+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
35+
»Unresolved« sub MyGlobalClass,
36+
}
37+
}
38+
39+
fun myMethod<T2>() where {
40+
// $TEST$ error "The left operand must refer to a type parameter of the declaration with the constraint."
41+
»T1« sub MyGlobalClass,
42+
43+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
44+
»T2« sub MyGlobalClass,
45+
46+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
47+
»Unresolved« sub MyGlobalClass,
48+
}
49+
}
50+
51+
enum MyGlobalEnum {
52+
MyEnumVariant<T1> where {
53+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
54+
»T1« sub MyGlobalClass,
55+
56+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
57+
»Unresolved« sub MyGlobalClass,
58+
}
59+
}
60+
61+
fun myGlobalFunction<T1>() where {
62+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
63+
»T1« sub MyGlobalClass,
64+
65+
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
66+
»Unresolved« sub MyGlobalClass,
67+
}

0 commit comments

Comments
 (0)