Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: error if left operand of type parameter constraint does not belong to declaration with constraint #571

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { isSdsDeclaration, SdsTypeParameterConstraint } from '../../../generated/ast.js';
import { getContainerOfType, ValidationAcceptor } from 'langium';

export const CODE_TYPE_PARAMETER_CONSTRAINT_LEFT_OPERAND = 'type-parameter-constraint/left-operand';

export const typeParameterConstraintLeftOperandMustBeOwnTypeParameter = (
node: SdsTypeParameterConstraint,
accept: ValidationAcceptor,
) => {
const typeParameter = node.leftOperand.ref;
if (!typeParameter) {
return;
}

const declarationWithConstraint = getContainerOfType(node.$container, isSdsDeclaration);
const declarationWithTypeParameters = getContainerOfType(typeParameter.$container, isSdsDeclaration);

if (declarationWithConstraint !== declarationWithTypeParameters) {
accept('error', 'The left operand must refer to a type parameter of the declaration with the constraint.', {
node,
property: 'leftOperand',
code: CODE_TYPE_PARAMETER_CONSTRAINT_LEFT_OPERAND,
});
}
};
2 changes: 2 additions & 0 deletions src/language/validation/safe-ds-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { templateStringMustHaveExpressionBetweenTwoStringParts } from './other/e
import { yieldMustNotBeUsedInPipeline } from './other/statements/assignments.js';
import { attributeMustHaveTypeHint, parameterMustHaveTypeHint, resultMustHaveTypeHint } from './types.js';
import { moduleDeclarationsMustMatchFileKind, moduleWithDeclarationsMustStatePackage } from './other/modules.js';
import { typeParameterConstraintLeftOperandMustBeOwnTypeParameter } from './other/declarations/typeParameterConstraints.js';

/**
* Register custom validation checks.
Expand All @@ -40,6 +41,7 @@ export const registerValidationChecks = function (services: SafeDsServices) {
SdsResult: [resultMustHaveTypeHint],
SdsSegment: [segmentResultListShouldNotBeEmpty],
SdsTemplateString: [templateStringMustHaveExpressionBetweenTwoStringParts],
SdsTypeParameterConstraint: [typeParameterConstraintLeftOperandMustBeOwnTypeParameter],
SdsUnionType: [unionTypeShouldNotHaveASingularTypeArgument],
SdsYield: [yieldMustNotBeUsedInPipeline],
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package tests.validation.other.declarations.typeParameterConstraints.typeParameterOnContainer

annotation MyAnnotation where {
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»Unresolved« sub MyGlobalClass,
}

class MyGlobalClass<T1> where {
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»T1« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»Unresolved« sub MyGlobalClass
} {
class MyNestedClass<T2> where {
// $TEST$ error "The left operand must refer to a type parameter of the declaration with the constraint."
»T1« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»T2« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»Unresolved« sub MyGlobalClass,
}

enum MyNestedEnum {
MyEnumVariant<T2> where {
// $TEST$ error "The left operand must refer to a type parameter of the declaration with the constraint."
»T1« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»T2« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»Unresolved« sub MyGlobalClass,
}
}

fun myMethod<T2>() where {
// $TEST$ error "The left operand must refer to a type parameter of the declaration with the constraint."
»T1« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»T2« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»Unresolved« sub MyGlobalClass,
}
}

enum MyGlobalEnum {
MyEnumVariant<T1> where {
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»T1« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»Unresolved« sub MyGlobalClass,
}
}

fun myGlobalFunction<T1>() where {
// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»T1« sub MyGlobalClass,

// $TEST$ no error "The left operand must refer to a type parameter of the declaration with the constraint."
»Unresolved« sub MyGlobalClass,
}