From f520f43a2ee8e80543a9a09834f86bc877be515b Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Sun, 4 Feb 2024 10:51:10 +0100 Subject: [PATCH 1/2] refactor: update node property helpers to handle undefined input --- .../src/language/helpers/nodeProperties.ts | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/safe-ds-lang/src/language/helpers/nodeProperties.ts b/packages/safe-ds-lang/src/language/helpers/nodeProperties.ts index c5cea3e29..1c6347379 100644 --- a/packages/safe-ds-lang/src/language/helpers/nodeProperties.ts +++ b/packages/safe-ds-lang/src/language/helpers/nodeProperties.ts @@ -1,6 +1,7 @@ import { AstNode, getContainerOfType, Stream, stream } from 'langium'; import { isSdsAnnotation, + isSdsArgument, isSdsArgumentList, isSdsAssignment, isSdsAttribute, @@ -78,29 +79,29 @@ export const hasAnnotationCallOf = ( }); }; -export const isInternal = (node: SdsDeclaration): boolean => { +export const isInternal = (node: SdsDeclaration | undefined): boolean => { return isSdsSegment(node) && node.visibility === 'internal'; }; export namespace Argument { - export const isNamed = (node: SdsArgument): boolean => { - return Boolean(node.parameter); + export const isNamed = (node: SdsArgument | undefined): boolean => { + return Boolean(node?.parameter); }; - export const isPositional = (node: SdsArgument): boolean => { - return !node.parameter; + export const isPositional = (node: SdsArgument | undefined): boolean => { + return isSdsArgument(node) && !node.parameter; }; } export namespace Enum { - export const isConstant = (node: SdsEnum): boolean => { - return getEnumVariants(node).every((it) => EnumVariant.isConstant(it)); + export const isConstant = (node: SdsEnum | undefined): boolean => { + return Boolean(node) && getEnumVariants(node).every((it) => EnumVariant.isConstant(it)); }; } export namespace EnumVariant { - export const isConstant = (node: SdsEnumVariant): boolean => { - return getParameters(node).every((it) => Parameter.isConstant(it)); + export const isConstant = (node: SdsEnumVariant | undefined): boolean => { + return Boolean(node) && getParameters(node).every((it) => Parameter.isConstant(it)); }; } @@ -129,7 +130,7 @@ export namespace Parameter { }; } -export const isStatic = (node: SdsClassMember): boolean => { +export const isStatic = (node: SdsClassMember | undefined): boolean => { if (isSdsClass(node) || isSdsEnum(node)) { return true; } else if (isSdsAttribute(node)) { @@ -143,8 +144,8 @@ export const isStatic = (node: SdsClassMember): boolean => { }; export namespace TypeArgument { - export const isNamed = (node: SdsTypeArgument): boolean => { - return Boolean(node.typeParameter); + export const isNamed = (node: SdsTypeArgument | undefined): boolean => { + return Boolean(node?.typeParameter); }; } From d6567067a6b505d3f261df15ca53fa0a1151fd68 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Sun, 4 Feb 2024 11:07:13 +0100 Subject: [PATCH 2/2] fix: allow usage of covariant type parameters in own constructor --- .../other/declarations/typeParameters.ts | 16 ++++++++++++++-- .../covariant type parameter.sdstest | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/safe-ds-lang/src/language/validation/other/declarations/typeParameters.ts b/packages/safe-ds-lang/src/language/validation/other/declarations/typeParameters.ts index 630e9f4ae..ca6346277 100644 --- a/packages/safe-ds-lang/src/language/validation/other/declarations/typeParameters.ts +++ b/packages/safe-ds-lang/src/language/validation/other/declarations/typeParameters.ts @@ -87,10 +87,17 @@ export const typeParameterMustBeUsedInCorrectPosition = (services: SafeDsService node: reference, code: CODE_TYPE_PARAMETER_USAGE, }); + return; // Don't show other errors for this reference + } + + // Usages in the **own constructor** are always correct. This check must come after the previous one, since + // that one filters out usages in **constructors of nested classes**. + if (isInConstructor(reference)) { + return; } // Check usage of variant type parameters - else if (TypeParameter.isContravariant(node)) { + if (TypeParameter.isContravariant(node)) { const position = getTypePosition(nodeMapper, declarationWithTypeParameter, reference); if (position !== 'contravariant') { @@ -113,6 +120,11 @@ export const typeParameterMustBeUsedInCorrectPosition = (services: SafeDsService }; }; +const isInConstructor = (node: AstNode) => { + const parameterList = getContainerOfType(node, isSdsParameterList); + return isSdsClass(parameterList?.$container); +}; + const classTypeParameterIsUsedInCorrectPosition = (classWithTypeParameter: SdsClass, reference: AstNode) => { const containingClassMember = getContainerOfType(reference, isSdsClassMember); @@ -121,7 +133,7 @@ const classTypeParameterIsUsedInCorrectPosition = (classWithTypeParameter: SdsCl return true; } - // Handle usage in static context + // Handle usage in static member if (isStatic(containingClassMember)) { return false; } diff --git a/packages/safe-ds-lang/tests/resources/validation/other/declarations/type parameters/usage of variant type parameter/covariant type parameter.sdstest b/packages/safe-ds-lang/tests/resources/validation/other/declarations/type parameters/usage of variant type parameter/covariant type parameter.sdstest index 7cce486c8..d34b7a833 100644 --- a/packages/safe-ds-lang/tests/resources/validation/other/declarations/type parameters/usage of variant type parameter/covariant type parameter.sdstest +++ b/packages/safe-ds-lang/tests/resources/validation/other/declarations/type parameters/usage of variant type parameter/covariant type parameter.sdstest @@ -1,6 +1,6 @@ package tests.validation.other.declarations.typeParameters.usageOfVariantTypeParameters -// $TEST$ error "A covariant type parameter cannot be used in contravariant position." +// $TEST$ no error r"A .*variant type parameter cannot be used in .*variant position." class MyClass2(p1: »Covariant«) { // $TEST$ no error r"A .*variant type parameter cannot be used in .*variant position." attr a1: »Covariant«