Skip to content

Commit

Permalink
feat: ensure that all assignees get a value (#630)
Browse files Browse the repository at this point in the history
Closes partially #543

### Summary of Changes

Show an error if an assignee might not get a value.

---------

Co-authored-by: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com>
  • Loading branch information
lars-reimann and megalinter-bot authored Oct 11, 2023
1 parent 01933b9 commit e8e2bf6
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 7 deletions.
1 change: 0 additions & 1 deletion language-configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
["(", ")"],
["{", "}"],
["[", "]"],
["<", ">"],
["»", "«"]
],
"autoClosingPairs": [
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/language/typing/safe-ds-type-computer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ export class SafeDsTypeComputer {
private readonly coreClasses: SafeDsClasses;
private readonly nodeMapper: SafeDsNodeMapper;

readonly typeCache: WorkspaceCache<string, Type>;
private readonly typeCache: WorkspaceCache<string, Type>;

constructor(readonly services: SafeDsServices) {
constructor(services: SafeDsServices) {
this.astNodeLocator = services.workspace.AstNodeLocator;
this.coreClasses = services.builtins.Classes;
this.nodeMapper = services.helpers.NodeMapper;
Expand Down
1 change: 0 additions & 1 deletion src/language/validation/other/expressions/references.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export const referenceMustNotBeFunctionPointer = (node: SdsReference, accept: Va
return;
}

//
let container: AstNode | undefined = node.$container;
if (isSdsMemberAccess(container) && node.$containerProperty === 'member') {
container = container.$container;
Expand Down
18 changes: 17 additions & 1 deletion src/language/validation/other/statements/assignments.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
import { isSdsPipeline, SdsYield } from '../../../generated/ast.js';
import { isSdsPipeline, SdsAssignment, SdsYield } from '../../../generated/ast.js';
import { getContainerOfType, ValidationAcceptor } from 'langium';
import { SafeDsServices } from '../../../safe-ds-module.js';
import { assigneesOrEmpty } from '../../../helpers/nodeProperties.js';

export const CODE_ASSIGMENT_NOTHING_ASSIGNED = 'assignment/nothing-assigned';
export const CODE_ASSIGMENT_YIELD_FORBIDDEN_IN_PIPELINE = 'assignment/yield-forbidden-in-pipeline';

export const assignmentAssigneeMustGetValue =
(services: SafeDsServices) =>
(node: SdsAssignment, accept: ValidationAcceptor): void => {
for (const assignee of assigneesOrEmpty(node)) {
if (!services.helpers.NodeMapper.assigneeToAssignedObjectOrUndefined(assignee)) {
accept('error', 'No value is assigned to this assignee.', {
node: assignee,
code: CODE_ASSIGMENT_NOTHING_ASSIGNED,
});
}
}
};

export const yieldMustNotBeUsedInPipeline = (node: SdsYield, accept: ValidationAcceptor): void => {
const containingPipeline = getContainerOfType(node, isSdsPipeline);

Expand Down
4 changes: 2 additions & 2 deletions src/language/validation/safe-ds-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
unionTypeShouldNotHaveASingularTypeArgument,
} from './style.js';
import { templateStringMustHaveExpressionBetweenTwoStringParts } from './other/expressions/templateStrings.js';
import { yieldMustNotBeUsedInPipeline } from './other/statements/assignments.js';
import { assignmentAssigneeMustGetValue, 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';
Expand Down Expand Up @@ -87,7 +87,7 @@ export const registerValidationChecks = function (services: SafeDsServices) {
assigneeAssignedResultShouldNotBeDeprecated(services),
assigneeAssignedResultShouldNotBeExperimental(services),
],
SdsAssignment: [assignmentShouldHaveMoreThanWildcardsAsAssignees],
SdsAssignment: [assignmentAssigneeMustGetValue(services), assignmentShouldHaveMoreThanWildcardsAsAssignees],
SdsAnnotation: [
annotationMustContainUniqueNames,
annotationParameterListShouldNotBeEmpty,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package tests.validation.other.statements.assignments.nothingAssigned

fun noResults()
fun oneResult() -> first: Int
fun twoResults() -> (first: Int, second: Int)

segment mySegment() -> (
r1: Any?,
r2: Any?,
r3: Any?,
r4: Any?,
r5: Any?,
r6: Any?,
r7: Any?,
r8: Any?,
r9: Any?,
r10: Any?,
r11: Any?,
r12: Any?,
r13: Any?,
r14: Any?,
) {
// $TEST$ error "No value is assigned to this assignee."
»_« = noResults();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»_«, »_« = oneResult();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»_«, »_«, »_« = twoResults();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»_«, »_« = 1;
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»_«, »_« = unresolved;
// $TEST$ error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»_«, »_« = unresolved();

// $TEST$ error "No value is assigned to this assignee."
»val a« = noResults();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»val b«, »val c« = oneResult();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»val d«, »val e«, »val f« = twoResults();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»val g«, »val h« = 1;
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»val i«, »val j« = unresolved;
// $TEST$ error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»val k«, »val l« = unresolved();

// $TEST$ error "No value is assigned to this assignee."
»yield r1« = noResults();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»yield r2«, »yield r3« = oneResult();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»yield r4«, »yield r5«, »yield r6« = twoResults();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»yield r7«, »yield r8« = 1;
// $TEST$ no error "No value is assigned to this assignee."
»yield r9« = oneResult();
// $TEST$ no error "No value is assigned to this assignee."
»yield r10« = twoResults();
// $TEST$ no error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»yield r11«, »yield r12« = unresolved;
// $TEST$ error "No value is assigned to this assignee."
// $TEST$ error "No value is assigned to this assignee."
»yield r13«, »yield r14« = unresolved();
}

0 comments on commit e8e2bf6

Please sign in to comment.