Skip to content

Commit

Permalink
feat: error if left operand of type parameter constraint does not bel…
Browse files Browse the repository at this point in the history
…ong 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>
  • Loading branch information
lars-reimann and megalinter-bot authored Sep 21, 2023
1 parent f6ffa4d commit cba3abf
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
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,
}

0 comments on commit cba3abf

Please sign in to comment.