diff --git a/ExtendedJavaScriptSubset.slnx b/ExtendedJavaScriptSubset.slnx
index 4932071c..94a939ee 100644
--- a/ExtendedJavaScriptSubset.slnx
+++ b/ExtendedJavaScriptSubset.slnx
@@ -51,6 +51,5 @@
-
\ No newline at end of file
diff --git a/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs b/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs
index 6c2e1bd0..73dc5b08 100644
--- a/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs
+++ b/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs
@@ -1,5 +1,6 @@
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Declarations;
using HydraScript.Domain.IR.Impl.Symbols;
+using HydraScript.Domain.IR.Impl.Symbols.Ids;
using ZLinq;
namespace HydraScript.Application.StaticAnalysis.Impl;
@@ -9,39 +10,45 @@ internal class TypeDeclarationsResolver(
ISymbolTableStorage symbolTables,
IVisitor typeBuilder) : ITypeDeclarationsResolver
{
- private readonly Queue _declarationsToResolve = [];
+ private readonly List _declarationsToResolve = [];
public void Store(TypeDeclaration declaration) =>
- _declarationsToResolve.Enqueue(declaration);
+ _declarationsToResolve.Add(declaration);
public void Resolve()
{
- var defaults = TypesService.GetDefaultTypes()
- .AsValueEnumerable()
- .Select(x => new TypeSymbol(x))
- .ToList();
-
- while (_declarationsToResolve.Count != 0)
+ // build phase
+ for (var i = 0; i < _declarationsToResolve.Count; i++)
{
- var declarationToResolve = _declarationsToResolve.Dequeue();
+ var declarationToResolve = _declarationsToResolve[i];
var typeSymbol = new TypeSymbol(
declarationToResolve.TypeValue.Accept(typeBuilder),
declarationToResolve.TypeId);
symbolTables[declarationToResolve.Scope].AddSymbol(typeSymbol);
+ }
- var resolvingCandidates = symbolTables[declarationToResolve.Scope]
- .GetAvailableSymbols()
+ var defaults = TypesService.GetDefaultTypes()
+ .AsValueEnumerable()
+ .Select(x => new TypeSymbol(x))
+ .ToList();
+
+ // resolve phase
+ for (var i = 0; i < _declarationsToResolve.Count; i++)
+ {
+ var symbolTable = symbolTables[_declarationsToResolve[i].Scope];
+ var typeSymbol = symbolTable.FindSymbol(new TypeSymbolId(_declarationsToResolve[i].TypeId))!;
+ var resolvingCandidates = symbolTable.GetAvailableSymbols()
.AsValueEnumerable()
.OfType()
.Except(defaults);
foreach (var referenceSymbol in resolvingCandidates)
{
- typeSymbol.Type.ResolveReference(
- referenceSymbol.Type,
- referenceSymbol.Name);
+ typeSymbol.Resolve(referenceSymbol);
}
}
+
+ _declarationsToResolve.Clear();
}
public IHydraScriptTypesService TypesService { get; } = typesService;
diff --git a/src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs b/src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs
index bf6a0818..ef6646f1 100644
--- a/src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs
+++ b/src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs
@@ -7,6 +7,11 @@ public class TypeSymbol(Type type, string? name = null) :
{
public override TypeSymbolId Id { get; } = new(name ?? type.ToString());
+ public void Resolve(TypeSymbol referenceSymbol) =>
+ Type.ResolveReference(
+ referenceSymbol.Type,
+ referenceSymbol.Name);
+
public override bool Equals(object? obj) =>
obj is TypeSymbol typeSymbol &&
Name == typeSymbol.Name && Type.Equals(typeSymbol.Type);
diff --git a/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs b/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs
new file mode 100644
index 00000000..2e9b2d9d
--- /dev/null
+++ b/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs
@@ -0,0 +1,85 @@
+using HydraScript.Application.StaticAnalysis.Impl;
+using HydraScript.Application.StaticAnalysis.Visitors;
+using HydraScript.Domain.FrontEnd.Parser;
+using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes;
+using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Declarations;
+using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Expressions.PrimaryExpressions;
+using HydraScript.Domain.IR.Impl;
+using HydraScript.Domain.IR.Impl.Symbols;
+using HydraScript.Domain.IR.Impl.Symbols.Ids;
+using HydraScript.Domain.IR.Types;
+
+namespace HydraScript.UnitTests.Application;
+
+///
+/// Тесты
+///
+public class TypeDeclarationsResolverTests
+{
+ ///
+ /// https://github.com/Stepami/hydrascript/issues/231
+ ///
+ [Fact]
+ public void Resolve_Issue231_Success()
+ {
+ // Arrange
+ const string itemTypeName = "QueryStringParseResultItem";
+ const string resultTypeName = "QueryStringParseResult";
+
+ var scope = new Scope();
+ var symbolTable = new SymbolTable();
+ symbolTable.AddSymbol(new TypeSymbol(itemTypeName));
+ symbolTable.AddSymbol(new TypeSymbol(resultTypeName));
+
+ var symbolTables = new SymbolTableStorage();
+ symbolTables.Init(scope, symbolTable);
+
+ var resolver = new TypeDeclarationsResolver(
+ new HydraScriptTypesService(),
+ symbolTables,
+ new TypeBuilder(symbolTables));
+
+ foreach (var defaultType in resolver.TypesService.GetDefaultTypes())
+ {
+ symbolTable.AddSymbol(new TypeSymbol(defaultType));
+ }
+
+ var resultDeclaration = new TypeDeclaration(
+ new IdentifierReference(resultTypeName),
+ new ObjectTypeValue(
+ [
+ new PropertyTypeValue(
+ "result",
+ new ArrayTypeValue(
+ new TypeIdentValue(
+ new IdentifierReference(itemTypeName)))),
+ ]));
+
+ var itemDeclaration = new TypeDeclaration(
+ new IdentifierReference(itemTypeName),
+ new ObjectTypeValue(
+ [
+ new PropertyTypeValue("name", TypeIdentValue.String),
+ new PropertyTypeValue("value", TypeIdentValue.String),
+ ]));
+
+ var root = new ScriptBody([resultDeclaration, itemDeclaration]);
+ root.InitScope(scope);
+ itemDeclaration.InitScope();
+ resultDeclaration.InitScope();
+
+ // Act
+ resolver.Store(resultDeclaration);
+ resolver.Store(itemDeclaration);
+
+ resolver.Resolve();
+
+ // Assert
+ var itemType = symbolTable.FindSymbol(new TypeSymbolId(itemTypeName))?.Type;
+ var resultType = symbolTable.FindSymbol(new TypeSymbolId(resultTypeName))?.Type as ObjectType;
+
+ itemType.Should().NotBeNull();
+ resultType.Should().NotBeNull();
+ resultType["result"].Should().Be(new ArrayType(itemType));
+ }
+}
\ No newline at end of file