Skip to content

Commit

Permalink
feat: error if too many type arguments are provided
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-reimann committed Oct 11, 2023
1 parent 0ccdeaa commit a268830
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 2 deletions.
23 changes: 22 additions & 1 deletion src/language/validation/other/types/namedTypes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { SdsNamedType } from '../../../generated/ast.js';
import { ValidationAcceptor } from 'langium';
import { SafeDsServices } from '../../../safe-ds-module.js';
import { typeArgumentsOrEmpty } from '../../../helpers/nodeProperties.js';
import { typeArgumentsOrEmpty, typeParametersOrEmpty } from '../../../helpers/nodeProperties.js';
import { duplicatesBy } from '../../../helpers/collectionUtils.js';
import { pluralize } from '../../../helpers/stringUtils.js';

export const CODE_NAMED_TYPE_DUPLICATE_TYPE_PARAMETER = 'named-type/duplicate-type-parameter';
export const CODE_NAMED_TYPE_POSITIONAL_AFTER_NAMED = 'named-type/positional-after-named';
export const CODE_NAMED_TYPE_TOO_MANY_TYPE_ARGUMENTS = 'named-type/too-many-type-arguments';

export const namedTypeMustNotSetTypeParameterMultipleTimes = (services: SafeDsServices) => {
const nodeMapper = services.helpers.NodeMapper;
Expand Down Expand Up @@ -46,3 +48,22 @@ export const namedTypeTypeArgumentListMustNotHavePositionalArgumentsAfterNamedAr
}
}
};

export const namedTypeMustNotHaveTooManyTypeArguments = (node: SdsNamedType, accept: ValidationAcceptor): void => {
// If the declaration is unresolved, we already show another error
if (!node.declaration.ref) {
return
}

const typeParameters = typeParametersOrEmpty(node.declaration.ref);
const typeArguments = typeArgumentsOrEmpty(node.typeArgumentList);

if (typeArguments.length > typeParameters.length) {
const kind = pluralize(typeParameters.length, 'type argument');
accept('error', `Expected ${typeParameters.length} ${kind} but got ${typeArguments.length}.`, {
node,
property: 'typeArgumentList',
code: CODE_NAMED_TYPE_TOO_MANY_TYPE_ARGUMENTS,
});
}
};
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 @@ -82,6 +82,7 @@ import { memberAccessMustBeNullSafeIfReceiverIsNullable } from './other/expressi
import { importPackageMustExist, importPackageShouldNotBeEmpty } from './other/imports.js';
import { singleUseAnnotationsMustNotBeRepeated } from './builtins/repeatable.js';
import {
namedTypeMustNotHaveTooManyTypeArguments,
namedTypeMustNotSetTypeParameterMultipleTimes,
namedTypeTypeArgumentListMustNotHavePositionalArgumentsAfterNamedArguments
} from "./other/types/namedTypes.js";
Expand Down Expand Up @@ -143,6 +144,7 @@ export const registerValidationChecks = function (services: SafeDsServices) {
SdsNamedType: [
namedTypeDeclarationShouldNotBeDeprecated(services),
namedTypeDeclarationShouldNotBeExperimental(services),
namedTypeMustNotHaveTooManyTypeArguments,
namedTypeMustNotSetTypeParameterMultipleTimes(services),
namedTypeMustSetAllTypeParameters(services),
namedTypeTypeArgumentListShouldBeNeeded,
Expand Down
2 changes: 1 addition & 1 deletion src/language/validation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const namedTypeMustSetAllTypeParameters =

const missingTypeParameters = expectedTypeParameters.filter((it) => !actualTypeParameters.includes(it));
if (!isEmpty(missingTypeParameters)) {
const kind = pluralize(missingTypeParameters.length, 'type parameter', 'type parameters');
const kind = pluralize(missingTypeParameters.length, 'type parameter');
const missingTypeParametersString = missingTypeParameters.map((it) => `'${it.name}'`).join(', ');

accept(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package tests.validation.other.types.typeArgumentLists.tooManyTypeArguments

class MyClass1<T>
class MyClass2<A, B>

fun myFunction(
// $TEST$ no error r"Expected \d* type arguments? but got \d*\."
f: MyClass1»<>«,
// $TEST$ no error r"Expected \d* type arguments? but got \d*\."
g: MyClass1»<Int>«,
// $TEST$ error "Expected 1 type argument but got 2."
h: MyClass1»<Int, Int>«,
// $TEST$ error "Expected 2 type arguments but got 3."
i: MyClass2»<Int, Int, Int>«,
// $TEST$ no error r"Expected \d* type arguments? but got \d*\."
j: Unresolved»<Int, Int>«
)

0 comments on commit a268830

Please sign in to comment.