Skip to content

Commit 6b486cd

Browse files
authored
feat: scoping of arguments (#601)
Closes partially #540. ### Summary of Changes Named arguments now correctly point to their corresponding parameter.
1 parent 8d68a42 commit 6b486cd

File tree

16 files changed

+332
-7
lines changed

16 files changed

+332
-7
lines changed

src/language/scoping/safe-ds-scope-provider.ts

+38-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ import {
1010
Scope,
1111
} from 'langium';
1212
import {
13+
isSdsAbstractCall,
14+
isSdsAnnotationCall,
15+
isSdsArgument,
1316
isSdsAssignment,
1417
isSdsBlock,
18+
isSdsCall,
1519
isSdsCallable,
1620
isSdsClass,
1721
isSdsEnum,
@@ -31,6 +35,7 @@ import {
3135
isSdsTypeArgument,
3236
isSdsWildcardImport,
3337
isSdsYield,
38+
SdsArgument,
3439
SdsDeclaration,
3540
SdsExpression,
3641
SdsImportedDeclaration,
@@ -61,6 +66,7 @@ import { isStatic } from '../helpers/checks.js';
6166
import { SafeDsServices } from '../safe-ds-module.js';
6267
import { SafeDsTypeComputer } from '../typing/safe-ds-type-computer.js';
6368
import { SafeDsPackageManager } from '../workspace/safe-ds-package-manager.js';
69+
import { CallableType, StaticType } from '../typing/model.js';
6470

6571
export class SafeDsScopeProvider extends DefaultScopeProvider {
6672
private readonly astReflection: AstReflection;
@@ -78,7 +84,9 @@ export class SafeDsScopeProvider extends DefaultScopeProvider {
7884
override getScope(context: ReferenceInfo): Scope {
7985
const node = context.container;
8086

81-
if (isSdsImportedDeclaration(node) && context.property === 'declaration') {
87+
if (isSdsArgument(node) && context.property === 'parameter') {
88+
return this.getScopeForArgumentParameter(node);
89+
} else if (isSdsImportedDeclaration(node) && context.property === 'declaration') {
8290
return this.getScopeForImportedDeclarationDeclaration(node);
8391
} else if (isSdsNamedType(node) && context.property === 'declaration') {
8492
if (isSdsMemberType(node.$container) && node.$containerProperty === 'member') {
@@ -101,6 +109,35 @@ export class SafeDsScopeProvider extends DefaultScopeProvider {
101109
}
102110
}
103111

112+
private getScopeForArgumentParameter(node: SdsArgument): Scope {
113+
const containingAbstractCall = getContainerOfType(node, isSdsAbstractCall);
114+
if (isSdsAnnotationCall(containingAbstractCall)) {
115+
const annotation = containingAbstractCall.annotation?.ref;
116+
if (!annotation) {
117+
return EMPTY_SCOPE;
118+
}
119+
120+
const parameters = parametersOrEmpty(annotation.parameterList);
121+
return this.createScopeForNodes(parameters);
122+
} else if (isSdsCall(containingAbstractCall)) {
123+
const receiverType = this.typeComputer.computeType(containingAbstractCall.receiver);
124+
if (receiverType instanceof CallableType) {
125+
const parameters = parametersOrEmpty(receiverType.sdsCallable.parameterList);
126+
return this.createScopeForNodes(parameters);
127+
} else if (receiverType instanceof StaticType) {
128+
const declaration = receiverType.instanceType.sdsDeclaration;
129+
if (isSdsCallable(declaration)) {
130+
const parameters = parametersOrEmpty(declaration.parameterList);
131+
return this.createScopeForNodes(parameters);
132+
}
133+
}
134+
135+
return EMPTY_SCOPE;
136+
} /* c8 ignore start */ else {
137+
return EMPTY_SCOPE;
138+
} /* c8 ignore stop */
139+
}
140+
104141
private getScopeForImportedDeclarationDeclaration(node: SdsImportedDeclaration): Scope {
105142
const ownPackageName = packageNameOrNull(node);
106143

src/language/typing/model.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class CallableType extends Type {
2323
override isNullable: boolean = false;
2424

2525
constructor(
26-
readonly callable: SdsCallable,
26+
readonly sdsCallable: SdsCallable,
2727
readonly inputType: NamedTupleType,
2828
readonly outputType: NamedTupleType,
2929
) {
@@ -48,7 +48,7 @@ export class CallableType extends Type {
4848
}
4949

5050
return (
51-
other.callable === this.callable &&
51+
other.sdsCallable === this.sdsCallable &&
5252
other.inputType.equals(this.inputType) &&
5353
other.outputType.equals(this.outputType)
5454
);

src/language/typing/safe-ds-type-computer.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -357,14 +357,12 @@ export class SafeDsTypeComputer {
357357
const receiverType = this.computeType(node.receiver);
358358

359359
if (receiverType instanceof CallableType) {
360-
if (!isSdsAnnotation(receiverType.callable)) {
360+
if (!isSdsAnnotation(receiverType.sdsCallable)) {
361361
return receiverType.outputType;
362362
}
363363
} else if (receiverType instanceof StaticType) {
364364
const instanceType = receiverType.instanceType;
365-
const declaration = instanceType.sdsDeclaration;
366-
367-
if (isSdsClass(declaration) || isSdsEnumVariant(declaration)) {
365+
if (isSdsCallable(instanceType.sdsDeclaration)) {
368366
return instanceType;
369367
}
370368
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package tests.scoping.arguments.ofAnnotationCalls.toParameter
2+
3+
annotation MyAnnotation(
4+
// $TEST$ target a
5+
»a«: Int,
6+
// $TEST$ target b
7+
»b«: Int = 0,
8+
// $TEST$ target c
9+
vararg »c«: Int
10+
)
11+
12+
@MyAnnotation(
13+
// $TEST$ references c
14+
»c« = 0,
15+
// $TEST$ references a
16+
»a« = 0,
17+
// $TEST$ references b
18+
»b« = 0
19+
)
20+
pipeline myPipeline {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package tests.scoping.arguments.ofAnnotationCalls.toSomethingOtherThanParameter
2+
3+
annotation MyAnnotation(a: Int)
4+
5+
@MyAnnotation(
6+
// $TEST$ unresolved
7+
»MyAnnotation« = 0,
8+
)
9+
pipeline myPipeline {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package tests.scoping.arguments.ofAnnotationCalls.unresolved
2+
3+
annotation MyAnnotation(a: Int)
4+
5+
@MyAnnotation(
6+
// $TEST$ unresolved
7+
»unresolved« = 0,
8+
)
9+
@Unresolved(
10+
// $TEST$ unresolved
11+
»a« = 0
12+
)
13+
pipeline myPipeline {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package tests.scoping.arguments.ofCalls.toParameterOfAnnotation
2+
3+
annotation MyAnnotation(
4+
// $TEST$ target a
5+
»a«: Int,
6+
// $TEST$ target b
7+
»b«: Int = 0,
8+
// $TEST$ target c
9+
vararg »c«: Int
10+
)
11+
12+
pipeline myPipeline {
13+
MyAnnotation(
14+
// $TEST$ references c
15+
»c« = 0,
16+
// $TEST$ references a
17+
»a« = 0,
18+
// $TEST$ references b
19+
»b« = 0
20+
);
21+
22+
val alias = MyAnnotation;
23+
alias(
24+
// $TEST$ references c
25+
»c« = 0,
26+
// $TEST$ references a
27+
»a« = 0,
28+
// $TEST$ references b
29+
»b« = 0
30+
);
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package tests.scoping.arguments.ofCalls.toParameterOfBlockLambda
2+
3+
pipeline myPipeline {
4+
val myBlockLambda = (
5+
// $TEST$ target a
6+
»a«: Int,
7+
// $TEST$ target b
8+
»b«: Int = 0,
9+
// $TEST$ target c
10+
vararg »c«: Int
11+
) {};
12+
13+
myBlockLambda(
14+
// $TEST$ references c
15+
»c« = 0,
16+
// $TEST$ references a
17+
»a« = 0,
18+
// $TEST$ references b
19+
»b« = 0
20+
);
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package tests.scoping.arguments.ofCalls.toParameterOfCallableType
2+
3+
segment mySegment(myCallableType: (
4+
// $TEST$ target a
5+
»a«: Int,
6+
// $TEST$ target b
7+
»b«: Int = 0,
8+
// $TEST$ target c
9+
vararg »c«: Int
10+
) -> ()) {
11+
myCallableType(
12+
// $TEST$ references c
13+
»c« = 0,
14+
// $TEST$ references a
15+
»a« = 0,
16+
// $TEST$ references b
17+
»b« = 0
18+
);
19+
20+
val alias = myCallableType;
21+
alias(
22+
// $TEST$ references c
23+
»c« = 0,
24+
// $TEST$ references a
25+
»a« = 0,
26+
// $TEST$ references b
27+
»b« = 0
28+
);
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package tests.scoping.arguments.ofCalls.toParameterOfClass
2+
3+
class MyClass(
4+
// $TEST$ target a
5+
»a«: Int,
6+
// $TEST$ target b
7+
»b«: Int = 0,
8+
// $TEST$ target c
9+
vararg »c«: Int
10+
) {}
11+
12+
pipeline myPipeline {
13+
MyClass(
14+
// $TEST$ references c
15+
»c« = 0,
16+
// $TEST$ references a
17+
»a« = 0,
18+
// $TEST$ references b
19+
»b« = 0
20+
);
21+
22+
val alias = MyClass;
23+
alias(
24+
// $TEST$ references c
25+
»c« = 0,
26+
// $TEST$ references a
27+
»a« = 0,
28+
// $TEST$ references b
29+
»b« = 0
30+
);
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package tests.scoping.arguments.ofCalls.toParameterOfEnumVariant
2+
3+
enum MyEnum {
4+
MyEnumVariant(
5+
// $TEST$ target a
6+
»a«: Int,
7+
// $TEST$ target b
8+
»b«: Int = 0,
9+
// $TEST$ target c
10+
vararg »c«: Int
11+
)
12+
}
13+
14+
15+
pipeline myPipeline {
16+
MyEnum.MyEnumVariant(
17+
// $TEST$ references c
18+
»c« = 0,
19+
// $TEST$ references a
20+
»a« = 0,
21+
// $TEST$ references b
22+
»b« = 0
23+
);
24+
25+
val alias = MyEnum.MyEnumVariant;
26+
alias(
27+
// $TEST$ references c
28+
»c« = 0,
29+
// $TEST$ references a
30+
»a« = 0,
31+
// $TEST$ references b
32+
»b« = 0
33+
);
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package tests.scoping.arguments.ofCalls.toParameterOfExpressionLambda
2+
3+
pipeline myPipeline {
4+
val myExpressionLambda = (
5+
// $TEST$ target a
6+
»a«: Int,
7+
// $TEST$ target b
8+
»b«: Int = 0,
9+
// $TEST$ target c
10+
vararg »c«: Int
11+
) -> 1;
12+
13+
myExpressionLambda(
14+
// $TEST$ references c
15+
»c« = 0,
16+
// $TEST$ references a
17+
»a« = 0,
18+
// $TEST$ references b
19+
»b« = 0
20+
);
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package tests.scoping.arguments.ofCalls.toParameterOfFunction
2+
3+
fun myFunction(
4+
// $TEST$ target a
5+
»a«: Int,
6+
// $TEST$ target b
7+
»b«: Int = 0,
8+
// $TEST$ target c
9+
vararg »c«: Int
10+
)
11+
12+
pipeline myPipeline {
13+
myFunction(
14+
// $TEST$ references c
15+
»c« = 0,
16+
// $TEST$ references a
17+
»a« = 0,
18+
// $TEST$ references b
19+
»b« = 0
20+
);
21+
22+
val alias = myFunction;
23+
alias(
24+
// $TEST$ references c
25+
»c« = 0,
26+
// $TEST$ references a
27+
»a« = 0,
28+
// $TEST$ references b
29+
»b« = 0
30+
);
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package tests.scoping.arguments.ofCalls.toParameterOfSegment
2+
3+
segment mySegment(
4+
// $TEST$ target a
5+
»a«: Int,
6+
// $TEST$ target b
7+
»b«: Int = 0,
8+
// $TEST$ target c
9+
vararg »c«: Int
10+
) {}
11+
12+
pipeline myPipeline {
13+
mySegment(
14+
// $TEST$ references c
15+
»c« = 0,
16+
// $TEST$ references a
17+
»a« = 0,
18+
// $TEST$ references b
19+
»b« = 0
20+
);
21+
22+
val alias = mySegment;
23+
alias(
24+
// $TEST$ references c
25+
»c« = 0,
26+
// $TEST$ references a
27+
»a« = 0,
28+
// $TEST$ references b
29+
»b« = 0
30+
);
31+
}

0 commit comments

Comments
 (0)