Skip to content

Commit cd84dd7

Browse files
authored
Merge pull request #4478 from 1c-syntax/fix/types-map-index-value
fix(types): индексатор соответствия даёт значение, а не пару ключ-значение
2 parents e85f3f6 + ff2f3ba commit cd84dd7

3 files changed

Lines changed: 104 additions & 2 deletions

File tree

src/main/java/com/github/_1c_syntax/bsl/languageserver/types/inferencer/ExpressionTypeInferencer.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -621,9 +621,27 @@ private TypeSet inferIndexAccess(BinaryOperationNode node, InferenceContext ctx)
621621
if (byName != null) {
622622
return byName;
623623
}
624-
TypeSet result = TypeSet.EMPTY;
624+
return elementsOfSequences(leftTypes);
625+
}
626+
627+
/**
628+
* Элементы последовательностных коллекций получателя.
629+
* <p>
630+
* Структуроподобные пропускаются: их индексатор даёт значение по ключу, а элемент
631+
* соответствия — пара «ключ и значение», и её отдают только обходу {@code Для Каждого}.
632+
* Состав ключей здесь уже известен пустым, то есть тип значения неизвестен; подставить
633+
* вместо него пару значило бы объявить у значения чужие члены, а его собственные —
634+
* несуществующими.
635+
*
636+
* @param leftTypes типы получателя.
637+
* @return объединение типов элементов; {@link TypeSet#EMPTY}, если элементов нет.
638+
*/
639+
private static TypeSet elementsOfSequences(TypeSet leftTypes) {
640+
var result = TypeSet.EMPTY;
625641
for (var ref : leftTypes.refs()) {
626-
result = result.union(leftTypes.getElementTypes(ref));
642+
if (!OpenDataObjectInference.isStructureOrMapLike(ref.qualifiedName())) {
643+
result = result.union(leftTypes.getElementTypes(ref));
644+
}
627645
}
628646
return result;
629647
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright (c) 2018-2026
5+
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Fedkin <nixel2007@gmail.com> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
package com.github._1c_syntax.bsl.languageserver.types;
23+
24+
import com.github._1c_syntax.bsl.languageserver.context.AbstractServerContextAwareTest;
25+
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
26+
import com.github._1c_syntax.bsl.languageserver.types.model.TypeRef;
27+
import com.github._1c_syntax.bsl.languageserver.types.model.TypeSet;
28+
import com.github._1c_syntax.bsl.languageserver.util.CleanupContextBeforeClassAndAfterClass;
29+
import com.github._1c_syntax.bsl.languageserver.util.TestUtils;
30+
import org.eclipse.lsp4j.Position;
31+
import org.junit.jupiter.api.Test;
32+
import org.springframework.beans.factory.annotation.Autowired;
33+
34+
import static org.assertj.core.api.Assertions.assertThat;
35+
36+
/**
37+
* Индексатор соответствия: {@code Соответствие[Ключ]} — это значение по ключу.
38+
* <p>
39+
* Парой «ключ и значение» соответствие отдаётся только обходу {@code Для Каждого}, и
40+
* подставлять её результату индексатора нельзя: обращение к свойству значения выглядело
41+
* бы тогда обращением к несуществующему члену пары.
42+
*/
43+
@CleanupContextBeforeClassAndAfterClass
44+
class MapIndexAccessTest extends AbstractServerContextAwareTest {
45+
46+
@Autowired
47+
private TypeService typeService;
48+
49+
@Test
50+
void indexAccessOnMapIsNotKeyAndValuePair() {
51+
// given / when: ключи соответствия в коде не вставлялись, поэтому их состав неизвестен.
52+
var types = at("Правило = Правила[ИмяПравила]", "Правило = ".length());
53+
54+
// then
55+
var names = types.refs().stream().map(TypeRef::qualifiedName).toList();
56+
assertThat(names.contains("КлючИЗначение"))
57+
.as("значение по ключу — не пара «ключ и значение», получено %s", names)
58+
.isFalse();
59+
}
60+
61+
private TypeSet at(String marker, int offsetInMarker) {
62+
var documentContext = doc();
63+
var content = documentContext.getContent();
64+
var markerStart = content.indexOf(marker);
65+
assertThat(markerStart).as("маркер '%s' найден в фикстуре", marker).isNotNegative();
66+
var targetOffset = markerStart + offsetInMarker;
67+
var lineStart = content.lastIndexOf('\n', targetOffset) + 1;
68+
var line = content.substring(0, targetOffset).split("\n").length - 1;
69+
var charInLine = targetOffset - lineStart;
70+
return typeService.expressionTypesAt(documentContext, new Position(line, charInLine + 1));
71+
}
72+
73+
private static DocumentContext doc() {
74+
return TestUtils.getDocumentContextFromFile("./src/test/resources/types/MapIndexAccess.bsl");
75+
}
76+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Функция ПравилоПоИмени(ИмяПравила)
2+
3+
Правила = Новый Соответствие;
4+
Правило = Правила[ИмяПравила];
5+
6+
Возврат Правило;
7+
8+
КонецФункции

0 commit comments

Comments
 (0)