diff --git a/src/language/scoping/safe-ds-scope-provider.ts b/src/language/scoping/safe-ds-scope-provider.ts index 34a44f6d7..afc1f4399 100644 --- a/src/language/scoping/safe-ds-scope-provider.ts +++ b/src/language/scoping/safe-ds-scope-provider.ts @@ -10,8 +10,12 @@ import { Scope, } from 'langium'; import { + isSdsAbstractCall, + isSdsAnnotationCall, + isSdsArgument, isSdsAssignment, isSdsBlock, + isSdsCall, isSdsCallable, isSdsClass, isSdsEnum, @@ -31,6 +35,7 @@ import { isSdsTypeArgument, isSdsWildcardImport, isSdsYield, + SdsArgument, SdsDeclaration, SdsExpression, SdsImportedDeclaration, @@ -61,6 +66,7 @@ import { isStatic } from '../helpers/checks.js'; import { SafeDsServices } from '../safe-ds-module.js'; import { SafeDsTypeComputer } from '../typing/safe-ds-type-computer.js'; import { SafeDsPackageManager } from '../workspace/safe-ds-package-manager.js'; +import { CallableType, StaticType } from '../typing/model.js'; export class SafeDsScopeProvider extends DefaultScopeProvider { private readonly astReflection: AstReflection; @@ -78,7 +84,9 @@ export class SafeDsScopeProvider extends DefaultScopeProvider { override getScope(context: ReferenceInfo): Scope { const node = context.container; - if (isSdsImportedDeclaration(node) && context.property === 'declaration') { + if (isSdsArgument(node) && context.property === 'parameter') { + return this.getScopeForArgumentParameter(node); + } else if (isSdsImportedDeclaration(node) && context.property === 'declaration') { return this.getScopeForImportedDeclarationDeclaration(node); } else if (isSdsNamedType(node) && context.property === 'declaration') { if (isSdsMemberType(node.$container) && node.$containerProperty === 'member') { @@ -101,6 +109,35 @@ export class SafeDsScopeProvider extends DefaultScopeProvider { } } + private getScopeForArgumentParameter(node: SdsArgument): Scope { + const containingAbstractCall = getContainerOfType(node, isSdsAbstractCall); + if (isSdsAnnotationCall(containingAbstractCall)) { + const annotation = containingAbstractCall.annotation?.ref; + if (!annotation) { + return EMPTY_SCOPE; + } + + const parameters = parametersOrEmpty(annotation.parameterList); + return this.createScopeForNodes(parameters); + } else if (isSdsCall(containingAbstractCall)) { + const receiverType = this.typeComputer.computeType(containingAbstractCall.receiver); + if (receiverType instanceof CallableType) { + const parameters = parametersOrEmpty(receiverType.sdsCallable.parameterList); + return this.createScopeForNodes(parameters); + } else if (receiverType instanceof StaticType) { + const declaration = receiverType.instanceType.sdsDeclaration; + if (isSdsCallable(declaration)) { + const parameters = parametersOrEmpty(declaration.parameterList); + return this.createScopeForNodes(parameters); + } + } + + return EMPTY_SCOPE; + } /* c8 ignore start */ else { + return EMPTY_SCOPE; + } /* c8 ignore stop */ + } + private getScopeForImportedDeclarationDeclaration(node: SdsImportedDeclaration): Scope { const ownPackageName = packageNameOrNull(node); diff --git a/src/language/typing/model.ts b/src/language/typing/model.ts index d791bdba7..22c10882c 100644 --- a/src/language/typing/model.ts +++ b/src/language/typing/model.ts @@ -23,7 +23,7 @@ export class CallableType extends Type { override isNullable: boolean = false; constructor( - readonly callable: SdsCallable, + readonly sdsCallable: SdsCallable, readonly inputType: NamedTupleType, readonly outputType: NamedTupleType, ) { @@ -48,7 +48,7 @@ export class CallableType extends Type { } return ( - other.callable === this.callable && + other.sdsCallable === this.sdsCallable && other.inputType.equals(this.inputType) && other.outputType.equals(this.outputType) ); diff --git a/src/language/typing/safe-ds-type-computer.ts b/src/language/typing/safe-ds-type-computer.ts index 142708c3f..f11429f5f 100644 --- a/src/language/typing/safe-ds-type-computer.ts +++ b/src/language/typing/safe-ds-type-computer.ts @@ -357,14 +357,12 @@ export class SafeDsTypeComputer { const receiverType = this.computeType(node.receiver); if (receiverType instanceof CallableType) { - if (!isSdsAnnotation(receiverType.callable)) { + if (!isSdsAnnotation(receiverType.sdsCallable)) { return receiverType.outputType; } } else if (receiverType instanceof StaticType) { const instanceType = receiverType.instanceType; - const declaration = instanceType.sdsDeclaration; - - if (isSdsClass(declaration) || isSdsEnumVariant(declaration)) { + if (isSdsCallable(instanceType.sdsDeclaration)) { return instanceType; } } diff --git a/tests/resources/scoping/arguments/of annotation calls/main.sdstest b/tests/resources/scoping/arguments/of annotation calls/to parameter/main.sdstest similarity index 83% rename from tests/resources/scoping/arguments/of annotation calls/main.sdstest rename to tests/resources/scoping/arguments/of annotation calls/to parameter/main.sdstest index 1341d883d..3fa6c7e51 100644 --- a/tests/resources/scoping/arguments/of annotation calls/main.sdstest +++ b/tests/resources/scoping/arguments/of annotation calls/to parameter/main.sdstest @@ -1,4 +1,4 @@ -package tests.scoping.arguments.ofAnnotationCalls +package tests.scoping.arguments.ofAnnotationCalls.toParameter annotation MyAnnotation( // $TEST$ target a diff --git a/tests/resources/scoping/arguments/of annotation calls/to something other than parameter/main.sdstest b/tests/resources/scoping/arguments/of annotation calls/to something other than parameter/main.sdstest new file mode 100644 index 000000000..a0edd6f00 --- /dev/null +++ b/tests/resources/scoping/arguments/of annotation calls/to something other than parameter/main.sdstest @@ -0,0 +1,9 @@ +package tests.scoping.arguments.ofAnnotationCalls.toSomethingOtherThanParameter + +annotation MyAnnotation(a: Int) + +@MyAnnotation( + // $TEST$ unresolved + »MyAnnotation« = 0, +) +pipeline myPipeline {} diff --git a/tests/resources/scoping/arguments/of annotation calls/unresolved/main.sdstest b/tests/resources/scoping/arguments/of annotation calls/unresolved/main.sdstest new file mode 100644 index 000000000..d391846e8 --- /dev/null +++ b/tests/resources/scoping/arguments/of annotation calls/unresolved/main.sdstest @@ -0,0 +1,13 @@ +package tests.scoping.arguments.ofAnnotationCalls.unresolved + +annotation MyAnnotation(a: Int) + +@MyAnnotation( + // $TEST$ unresolved + »unresolved« = 0, +) +@Unresolved( + // $TEST$ unresolved + »a« = 0 +) +pipeline myPipeline {}