From 19f90bd66a28aa58dc4c19e88e0b36d0999f2c01 Mon Sep 17 00:00:00 2001 From: Paulo Mattos Date: Mon, 14 Dec 2020 22:15:10 -0300 Subject: [PATCH 1/9] Faz bind de tipos aninhados --- .../Syntax/Binding/BinderTests.cs | 23 +++++++++++++++++++ src/Compiler/CodeAnalysis/Binding/Binder.cs | 13 ++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs index e5a59d3..04ca6fb 100644 --- a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs +++ b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs @@ -1365,6 +1365,29 @@ enum TestEnum AssertDiagnostics(text, diagnostics); } + [Fact] + public void Binder_TypeDeclaration_NestedType() + { + var text = @" + struct Line + { + var p1 : Point + var p2 : Point + + struct Point + { + var x : int + var y : int + } + }"; + + var diagnostics = new List() + { + }; + + AssertDiagnostics(text, diagnostics); + } + /* [Fact] public void Binder_IfStatement_Reports_UnreachableCode_Warning() diff --git a/src/Compiler/CodeAnalysis/Binding/Binder.cs b/src/Compiler/CodeAnalysis/Binding/Binder.cs index dbebd67..67efb52 100644 --- a/src/Compiler/CodeAnalysis/Binding/Binder.cs +++ b/src/Compiler/CodeAnalysis/Binding/Binder.cs @@ -213,6 +213,13 @@ private void BindMemberBlockStatement(MemberBlockStatementSyntax syntax, List()) + { + BindTypeDeclaration(statementSyntax); + } + foreach (var statementSyntax in syntax.Statement) { switch (statementSyntax.Kind) @@ -249,7 +256,11 @@ private void BindMemberBlockStatement(MemberBlockStatementSyntax syntax, List Date: Tue, 15 Dec 2020 11:57:41 -0300 Subject: [PATCH 2/9] =?UTF-8?q?Emi=C3=A7=C3=A3o=20de=20tipos=20declarados?= =?UTF-8?q?=20de=20forma=20aninhada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ainda não é possivel acessar esses tipos --- Samples/NestedType/.vscode/launch.json | 28 ++++++ Samples/NestedType/.vscode/tasks.json | 24 +++++ Samples/NestedType/NestedType.out | 4 + Samples/NestedType/NestedType.pys | 27 +++++ Samples/NestedType/NestedType.pysproj | 6 ++ .../ConsoleOutputTests.cs | 1 + src/Compiler/CodeAnalysis/Binding/Binder.cs | 23 ++++- src/Compiler/CodeAnalysis/Emit/Emitter.cs | 99 ++++++++++++++----- .../CodeAnalysis/Symbols/FieldSymbol.cs | 13 ++- 9 files changed, 190 insertions(+), 35 deletions(-) create mode 100644 Samples/NestedType/.vscode/launch.json create mode 100644 Samples/NestedType/.vscode/tasks.json create mode 100644 Samples/NestedType/NestedType.out create mode 100644 Samples/NestedType/NestedType.pys create mode 100644 Samples/NestedType/NestedType.pysproj diff --git a/Samples/NestedType/.vscode/launch.json b/Samples/NestedType/.vscode/launch.json new file mode 100644 index 0000000..078d2e2 --- /dev/null +++ b/Samples/NestedType/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/struct.dll", + "args": [], + "cwd": "${workspaceFolder}/bin/Debug/", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "integratedTerminal", + "stopAtEntry": false, + "internalConsoleOptions": "openOnSessionStart" + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/Samples/NestedType/.vscode/tasks.json b/Samples/NestedType/.vscode/tasks.json new file mode 100644 index 0000000..31c32bd --- /dev/null +++ b/Samples/NestedType/.vscode/tasks.json @@ -0,0 +1,24 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "shell", + "args": [ + "build", + // Ask dotnet build to generate full paths for file names. + "/property:GenerateFullPaths=true", + // Do not generate summary otherwise it leads to duplicate errors in Problems panel + "/consoleloggerparameters:NoSummary" + ], + "group": "build", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Samples/NestedType/NestedType.out b/Samples/NestedType/NestedType.out new file mode 100644 index 0000000..f2b6d30 --- /dev/null +++ b/Samples/NestedType/NestedType.out @@ -0,0 +1,4 @@ +10 +10 +100 +100 diff --git a/Samples/NestedType/NestedType.pys b/Samples/NestedType/NestedType.pys new file mode 100644 index 0000000..ad4dc71 --- /dev/null +++ b/Samples/NestedType/NestedType.pys @@ -0,0 +1,27 @@ +struct Rect +{ + var p1: Vector2Int = Vector2Int() + var p2: Vector2Int = Vector2Int() + + struct Vector2Int + { + var x : int + var y : int + } +} + + +function main() +{ + var rect = Rect() + rect.p1 = Rect.Point() +/* + rect.p1.y = 10 + rect.p2.x = 100 + rect.p2.y = 100 +*/ + print(rect.p1.x) + print(rect.p1.y) + print(rect.p2.x) + print(rect.p2.y) +} \ No newline at end of file diff --git a/Samples/NestedType/NestedType.pysproj b/Samples/NestedType/NestedType.pysproj new file mode 100644 index 0000000..efa7319 --- /dev/null +++ b/Samples/NestedType/NestedType.pysproj @@ -0,0 +1,6 @@ + + + Exe + netcoreapp3.1 + + \ No newline at end of file diff --git a/src/Compiler.Tests.Samples/ConsoleOutputTests.cs b/src/Compiler.Tests.Samples/ConsoleOutputTests.cs index 23d7cc9..2ee3ea3 100644 --- a/src/Compiler.Tests.Samples/ConsoleOutputTests.cs +++ b/src/Compiler.Tests.Samples/ConsoleOutputTests.cs @@ -27,6 +27,7 @@ public ConsoleOutputTests(ITestOutputHelper output) [InlineData("IsEven", "2", "10", "5")] [InlineData("Enum")] [InlineData("Struct")] + // [InlineData("NestedType")] public async Task SamplesTests(string filenamePrefix, params string[] inputs) { var psi = new ProcessStartInfo diff --git a/src/Compiler/CodeAnalysis/Binding/Binder.cs b/src/Compiler/CodeAnalysis/Binding/Binder.cs index 67efb52..30399c5 100644 --- a/src/Compiler/CodeAnalysis/Binding/Binder.cs +++ b/src/Compiler/CodeAnalysis/Binding/Binder.cs @@ -99,6 +99,16 @@ private void BindTypeDeclaration(TypeDeclarationSyntax typeDeclarationSyntax) } _scope.TryDeclareType(type); + + _scope = type.BoundScope!; + + // Declare all nested types + foreach (var statementSyntax in typeDeclarationSyntax.Body.Statement.OfType()) + { + BindTypeDeclaration(statementSyntax); + } + + _scope = type.BoundScope!.Parent!; } public static BoundProgram BindProgram(BoundGlobalScope globalScope) @@ -213,11 +223,15 @@ private void BindMemberBlockStatement(MemberBlockStatementSyntax syntax, List()) { - BindTypeDeclaration(statementSyntax); + var nestedType = typeScope.TryLookupSymbol(statementSyntax.Identifier.Text); + Debug.Assert(nestedType != null); + Debug.Assert(nestedType.BoundScope != null); + + var binder = new Binder(nestedType.BoundScope, null, nestedType); + binder.BindMemberBlockStatement(nestedType.Declaration!.Body, functionsToLower); + Diagnostics.AddRange(binder.Diagnostics); } foreach (var statementSyntax in syntax.Statement) @@ -380,7 +394,8 @@ private FieldSymbol BindEnumElementStatement(EnumSymbol enumSymbol, EnumSyntax s nextValue = (int)boundValueExpression.ConstantValue!.Value; } var variable = BindVariableDeclaration(syntax.Identifier, true, true, VariableKind.Local, variableType, new BoundConstant(nextValue), false); - return new FieldSymbol(variable); + var initializer = new BoundLiteralExpression(syntax, enumSymbol, nextValue); + return new FieldSymbol(variable, initializer); } private BoundExpression BindSyntheticDefaultExpression(VariableDeclarationStatementSyntax syntax, TypeSymbol type) diff --git a/src/Compiler/CodeAnalysis/Emit/Emitter.cs b/src/Compiler/CodeAnalysis/Emit/Emitter.cs index ce19f6a..e637c96 100644 --- a/src/Compiler/CodeAnalysis/Emit/Emitter.cs +++ b/src/Compiler/CodeAnalysis/Emit/Emitter.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using Compiler.CodeAnalysis.Binding; +using Compiler.CodeAnalysis.Binding.Scopes; using Compiler.CodeAnalysis.Diagnostics; using Compiler.CodeAnalysis.Symbols; using Compiler.CodeAnalysis.Syntax; @@ -12,11 +13,23 @@ using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; +using Mono.Collections.Generic; namespace Compiler.CodeAnalysis.Emit { internal class Emitter { + const TypeAttributes _enumAttributes = TypeAttributes.Class + | TypeAttributes.NotPublic + | TypeAttributes.AnsiClass + | TypeAttributes.Sealed; + + const TypeAttributes _structAttributes = TypeAttributes.Class + //| TypeAttributes.Public + | TypeAttributes.SequentialLayout + | TypeAttributes.AnsiClass + | TypeAttributes.Sealed + | TypeAttributes.BeforeFieldInit; private readonly DiagnosticBag _diagnostics; private readonly AssemblyDefinition _assemblyDefinition; private readonly TypeDefinition _typeDefinition; @@ -260,6 +273,8 @@ private void EmitTypeDeclarations(ImmutableArray types) private void EmitTypeBody(TypeSymbol typeSymbol) { + Debug.Assert(typeSymbol.BoundScope != null); + var typeDefinition = _declaredTypes[typeSymbol]; EmitFields(typeSymbol, typeDefinition); @@ -275,6 +290,13 @@ private void EmitTypeBody(TypeSymbol typeSymbol) default: throw new InvalidOperationException($"Unexpected declaration kind {typeSymbol.Declaration.TypeKind}"); } + + + var nestedTypes = typeSymbol.BoundScope.GetDeclaredSymbols(); + foreach (var nestedType in nestedTypes) + { + EmitTypeBody(nestedType); + } } private void EmitFields(TypeSymbol typeSymbol, TypeDefinition typeDefinition) @@ -308,19 +330,33 @@ private void EmitFields(TypeSymbol typeSymbol, TypeDefinition typeDefinition) private void EmitTypeDeclaration(TypeSymbol typeSymbol) { + Debug.Assert(typeSymbol.BoundScope != null); + + TypeAttributes? modifiers = null; + if (typeSymbol.BoundScope.Parent is TypeBoundScope) + { + modifiers = TypeAttributes.NestedPublic; + } + switch (typeSymbol.Declaration!.TypeKind) { case TypeDeclarationKind.Enum: - EmitEnumDeclaration((EnumSymbol)typeSymbol); + EmitEnumDeclaration((EnumSymbol)typeSymbol, modifiers); break; case TypeDeclarationKind.Struct: - EmitStructDeclaration((StructSymbol)typeSymbol); + EmitStructDeclaration((StructSymbol)typeSymbol, modifiers); break; default: throw new InvalidOperationException($"Unexpected declaration kind {typeSymbol.Declaration.TypeKind}"); } + + var nestedTypes = typeSymbol.BoundScope.GetDeclaredSymbols(); + foreach (var nestedType in nestedTypes) + { + EmitTypeDeclaration(nestedType); + } } private void EmitFunctionDeclarations(ImmutableDictionary functions) @@ -405,39 +441,55 @@ private void EmitFunctionBody(FunctionSymbol function, BoundBlockStatement body) } } - private void EmitEnumDeclaration(EnumSymbol enumSymbol) + private void EmitEnumDeclaration(EnumSymbol enumSymbol, TypeAttributes? modifiers) { - const TypeAttributes _enumAttributes = TypeAttributes.Class - | TypeAttributes.NotPublic - | TypeAttributes.AnsiClass - | TypeAttributes.Sealed; const FieldAttributes _enumSpecialAttributes = FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName; - var enumType = new TypeDefinition("", enumSymbol.Name, _enumAttributes, Import(TypeSymbol.Enum)); - _assemblyDefinition.MainModule.Types.Add(enumType); + var attributes = _enumAttributes; + if (modifiers.HasValue) + { + attributes |= modifiers.Value; + } + + var enumType = new TypeDefinition("", enumSymbol.Name, attributes, Import(TypeSymbol.Enum)); + GetCollectionFor(enumSymbol).Add(enumType); _declaredTypes.Add(enumSymbol, enumType); _resolvedTypes.Add(enumSymbol, enumType); var specialField = new FieldDefinition("value__", _enumSpecialAttributes, Import(TypeSymbol.Int)); enumType.Fields.Add(specialField); } + + private Collection GetCollectionFor(TypeSymbol type) + { + Debug.Assert(type.BoundScope != null); + if (type.BoundScope.Parent is not TypeBoundScope parentScope) + { + return _assemblyDefinition.MainModule.Types; + } + if (type.BoundScope.Parent == null) + { + return _assemblyDefinition.MainModule.Types; + } + var parentType = parentScope.OwnerType; + var parentTypeDefinition = _declaredTypes[parentType]; + return parentTypeDefinition.NestedTypes; + } - private void EmitStructDeclaration(StructSymbol structSymbol) + private void EmitStructDeclaration(StructSymbol structSymbol, TypeAttributes? modifiers) { - const TypeAttributes _structAttributes = TypeAttributes.Class - | TypeAttributes.Public - | TypeAttributes.SequentialLayout - | TypeAttributes.AnsiClass - | TypeAttributes.Sealed - | TypeAttributes.BeforeFieldInit; - - var structType = new TypeDefinition("", structSymbol.Name, _structAttributes, Import(TypeSymbol.Struct)); - _assemblyDefinition.MainModule.Types.Add(structType); + var attributes = _structAttributes; + if (modifiers.HasValue) + { + attributes |= modifiers.Value; + } + var structType = new TypeDefinition("", structSymbol.Name, attributes, Import(TypeSymbol.Struct)); + GetCollectionFor(structSymbol).Add(structType); _declaredTypes.Add(structSymbol, structType); _resolvedTypes.Add(structSymbol, structType); - + // Forward-declare empty constructor var emptyCtorDefinition = new MethodDefinition( ".ctor", @@ -459,14 +511,12 @@ private void EmitEmptyConstructorForStruct(StructSymbol structSymbol, TypeDefini { // Get empty constructor declaration var constructor = typeDefinition.Methods[0]; - var ilProcessor = constructor.Body.GetILProcessor(); foreach (var field in structSymbol.Members.OfType()) { var fieldDefinition = typeDefinition.Fields.Single(f => f.Name == field.Name); - var defaultValue = new BoundLiteralExpression(null!, field.Type, field.Type.DefaultValue!); - EmitFieldAssignment(ilProcessor, defaultValue, fieldDefinition); + EmitFieldAssignment(ilProcessor, field.Initializer, fieldDefinition); } ilProcessor.Emit(OpCodes.Ret); @@ -675,7 +725,6 @@ private static void EmitTypeReferenceExpression(ILProcessor ilProcessor, BoundTy private static void EmitConstantExpression(ILProcessor ilProcessor, BoundExpression node) { Debug.Assert(node.ConstantValue != null); - if (node.Type == TypeSymbol.Bool) { var value = (bool)node.ConstantValue.Value; @@ -949,7 +998,6 @@ private void EmitCallExpression(ILProcessor ilProcessor, BoundCallExpression nod else if (node.Symbol.Name.Equals(".ctor")) { var className = function.ReturnType.Name; - Console.WriteLine(className); var structSymbol = _declaredTypes.First(s => s.Key.Name == className).Value; // TODO: We should use a general overload resolution algorithm instead @@ -1081,7 +1129,6 @@ private static void EmitFieldAccessExpression(ILProcessor ilProcessor, FieldSymb for (var i = 0; i < method.Parameters.Count; i++) { var other = method.Parameters[i]; - Console.WriteLine(other.Name); if (other.Name == parameter.Name) { return i + (method.HasThis ? 1 : 0); diff --git a/src/Compiler/CodeAnalysis/Symbols/FieldSymbol.cs b/src/Compiler/CodeAnalysis/Symbols/FieldSymbol.cs index 0133ac4..a86333b 100644 --- a/src/Compiler/CodeAnalysis/Symbols/FieldSymbol.cs +++ b/src/Compiler/CodeAnalysis/Symbols/FieldSymbol.cs @@ -5,31 +5,34 @@ namespace Compiler.CodeAnalysis.Symbols { public sealed class FieldSymbol : MemberSymbol { + internal BoundExpression Initializer { get; } public override MemberKind MemberKind => MemberKind.Field; + private FieldSymbol(SyntaxNode? syntax, string name, bool isReadOnly, bool isStatic, TypeSymbol type, - BoundConstant? constant) - : base(syntax, name, isReadOnly, isStatic, type, constant) + BoundExpression initializer) + : base(syntax, name, isReadOnly, isStatic, type, initializer.ConstantValue) { + Initializer = initializer; } - internal FieldSymbol(VariableSymbol variable) + internal FieldSymbol(VariableSymbol variable, BoundExpression initializer) : this(variable.Syntax, variable.Name, variable.IsReadOnly, variable.IsStatic, variable.Type, - variable.Constant) + initializer) { } internal FieldSymbol(BoundVariableDeclarationStatement declaration) - : this(declaration.Variable) + : this(declaration.Variable, declaration.Initializer) { } } From c1887ee9401574258cfde4df8a27c56f609d3d85 Mon Sep 17 00:00:00 2001 From: Paulo Mattos Date: Wed, 16 Dec 2020 21:23:42 -0300 Subject: [PATCH 3/9] Modifica bind --- Samples/NestedType/NestedType.pys | 7 +- .../Syntax/Binding/BinderTests.cs | 42 +++++++- src/Compiler/CodeAnalysis/Binding/Binder.cs | 98 ++++++------------- .../Syntax/MemberAccessExpressionSyntax.cs | 4 +- 4 files changed, 75 insertions(+), 76 deletions(-) diff --git a/Samples/NestedType/NestedType.pys b/Samples/NestedType/NestedType.pys index ad4dc71..5ce9e7a 100644 --- a/Samples/NestedType/NestedType.pys +++ b/Samples/NestedType/NestedType.pys @@ -1,7 +1,7 @@ struct Rect { - var p1: Vector2Int = Vector2Int() - var p2: Vector2Int = Vector2Int() + var p1: Vector2Int + var p2: Vector2Int struct Vector2Int { @@ -14,8 +14,9 @@ struct Rect function main() { var rect = Rect() + /* rect.p1 = Rect.Point() -/* + rect.p1.y = 10 rect.p2.x = 100 rect.p2.y = 100 diff --git a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs index 04ca6fb..faa151d 100644 --- a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs +++ b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs @@ -926,13 +926,13 @@ function main() { var p: int = 0 p.[length] = 10 - p.[length()] + p.[length]() } "; var diagnostics = new List() { - DiagnosticCode.CannotAccessMember.GetDiagnostic("length", "int"), - DiagnosticCode.CannotAccessMember.GetDiagnostic("length", "int"), + DiagnosticCode.UndefinedName.GetDiagnostic("length"), + DiagnosticCode.UndefinedFunction.GetDiagnostic("length"), }; AssertDiagnostics(text, diagnostics); } @@ -1313,13 +1313,13 @@ function f() : int function printTest(t : TestStruct) { - t.f [=] 10 + t.[f] = 10 } "; var diagnostics = new List() { - DiagnosticCode.CannotAssignMethod.GetDiagnostic("f", "TestStruct") + DiagnosticCode.NotAVariable.GetDiagnostic("f") }; AssertDiagnostics(text, diagnostics); @@ -1387,6 +1387,38 @@ struct Point AssertDiagnostics(text, diagnostics); } + + [Fact] + public void Binder_VariableDeclaration_NestedType() + { + var text = @" + struct Line + { + var p1 : Point + var p2 : Point + + struct Point + { + var x : int + var y : int + + struct Point1 + { + } + } + } + + function main() + { + var p = Line.Point.Point1() + }"; + + var diagnostics = new List() + { + }; + + AssertDiagnostics(text, diagnostics); + } /* [Fact] diff --git a/src/Compiler/CodeAnalysis/Binding/Binder.cs b/src/Compiler/CodeAnalysis/Binding/Binder.cs index 30399c5..05b4ac0 100644 --- a/src/Compiler/CodeAnalysis/Binding/Binder.cs +++ b/src/Compiler/CodeAnalysis/Binding/Binder.cs @@ -185,7 +185,7 @@ private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax) } else { - var parameter = VariableSymbol.Parameter(parameterSyntax, parameterName, false, parameterType); + var parameter = VariableSymbol.Parameter(parameterSyntax, parameterName, false, parameterType); parameters.Add(parameter); } } @@ -198,7 +198,7 @@ private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax) syntax, _scope, receiver); - + _scope.TryDeclareFunction(function); return function; } @@ -449,14 +449,14 @@ private VariableSymbol BindVariableDeclaration(SyntaxToken identifier, bool isRe var declare = !identifier.IsMissing; var name = declare ? identifier.Text : "?"; var variable = VariableSymbol.New(identifier, name, isReadOnly, isStatic, kind, type, constant); - + if (declare && addToScope) { _scope.TryDeclareVariable(variable); } return variable; } - + private Symbol? BindSymbolReference(SyntaxToken identifier, TextLocation location) { switch (_scope.TryLookupSymbol(identifier.Text)) @@ -793,7 +793,8 @@ private BoundExpression BindCallExpression(CallExpressionSyntax syntax) if (symbol is TypeSymbol ts) { - symbol = GetMemberSymbol(ts, ".ctor"); + Debug.Assert(ts.BoundScope != null); + symbol = ts.BoundScope.TryLookupSymbol(".ctor"); } if (symbol is not FunctionSymbol function) @@ -874,73 +875,42 @@ private BoundExpression BindCallExpression(CallExpressionSyntax syntax, Function private BoundExpression BindMemberAccessExpression(MemberAccessExpressionSyntax syntax) { - BoundExpression nameExpression; - if (syntax.ParentExpression.Kind == SyntaxKind.MemberAccessExpression) - { - return BindMemberAccessExpression((MemberAccessExpressionSyntax)syntax.ParentExpression); - } - else + var originalScope = _scope; + BoundExpression receiverExpression; + var stack = new Stack(); + ExpressionSyntax parent = syntax.ParentExpression; + + if (parent.Kind == SyntaxKind.MemberAccessExpression) { - nameExpression = BindNameExpression((NameExpressionSyntax)syntax.ParentExpression, true); - switch (syntax.MemberExpression.Kind) + while (parent is MemberAccessExpressionSyntax access) { - case SyntaxKind.CallExpression: - var functionSymbol = GetMemberSymbol(nameExpression.Type, syntax.IdentifierToken.Text); - if (functionSymbol != null) - { - var boundCall = (BoundCallExpression)BindCallExpression((CallExpressionSyntax)syntax.MemberExpression, functionSymbol); - return new BoundMemberAccessExpression(syntax, nameExpression, boundCall); - } - break; - - default: - var member = BindMemberReference(nameExpression.Type, syntax); - if (member != null) - { - return new BoundMemberAccessExpression(syntax, nameExpression, member); - } - break; + stack.Push(access.MemberExpression); + parent = access.ParentExpression; } } - Diagnostics.ReportCannotAccessMember(syntax.MemberExpression.Location, nameExpression.Type.Name, syntax.MemberExpression.IdentifierToken.Text); - return new BoundErrorExpression(syntax); - } - - private static BoundMemberExpression? BindMemberReference(TypeSymbol typeSymbol, MemberAccessExpressionSyntax syntax) - { - var memberSymbol = GetMemberSymbol(typeSymbol, syntax.IdentifierToken.Text); - if (memberSymbol != null) + stack.Push((NameExpressionSyntax)parent); + do { - return new BoundMemberExpression(syntax, memberSymbol); - } - return null; - } + // Advance the scope trough the nested access + var exp = stack.Pop(); + receiverExpression = BindNameExpression(exp); + Debug.Assert(receiverExpression.Type.BoundScope != null); + _scope = receiverExpression.Type.BoundScope; + } while (stack.Count > 0); - private static T? GetMemberSymbol(TypeSymbol typeSymbol, string memberName) where T : MemberSymbol - { - foreach (var member in typeSymbol.Members.OfType()) - { - if (member.Name == memberName) - { - return member; - } - } - return null; - } + var memberExpression = BindExpression(syntax.MemberExpression, true); - private static MemberSymbol? GetMemberSymbol(TypeSymbol typeSymbol, string memberName) - { - foreach (var member in typeSymbol.Members) + // Return to the original binder scope + _scope = originalScope; + + if (memberExpression.Kind == BoundNodeKind.ErrorExpression) { - if (member.Name == memberName) - { - return member; - } + return memberExpression; } - return null; + return new BoundMemberAccessExpression(syntax, receiverExpression, (BoundMemberExpression)memberExpression); } - + private BoundExpression BindConversion(ExpressionSyntax syntax, TypeSymbol type, bool allowExplicit = false) { var expression = BindExpression(syntax); @@ -1002,11 +972,7 @@ private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byR case SymbolKind.Member: - var selfKeyword = new SyntaxToken(syntax.SyntaxTree, SyntaxKind.SelfKeyword, syntax.Span.End, "self", null, ImmutableArray.Empty, ImmutableArray.Empty); - var injectedSelf = new SelfKeywordSyntax(syntax.SyntaxTree, selfKeyword); - var dotToken = new SyntaxToken(syntax.SyntaxTree, SyntaxKind.DotToken, syntax.Span.End, ".", null, ImmutableArray.Empty, ImmutableArray.Empty); - var memberAccess = new MemberAccessExpressionSyntax(syntax.SyntaxTree, injectedSelf, dotToken, syntax); - return BindMemberAccessExpression(memberAccess); + return new BoundMemberExpression(syntax, (MemberSymbol)symbol); case SymbolKind.Type: case SymbolKind.Enum: diff --git a/src/Compiler/CodeAnalysis/Syntax/MemberAccessExpressionSyntax.cs b/src/Compiler/CodeAnalysis/Syntax/MemberAccessExpressionSyntax.cs index bd0a2df..7f4fac5 100644 --- a/src/Compiler/CodeAnalysis/Syntax/MemberAccessExpressionSyntax.cs +++ b/src/Compiler/CodeAnalysis/Syntax/MemberAccessExpressionSyntax.cs @@ -4,14 +4,14 @@ namespace Compiler.CodeAnalysis.Syntax { public sealed partial class MemberAccessExpressionSyntax : NameExpressionSyntax { - public ExpressionSyntax ParentExpression { get; } + public NameExpressionSyntax ParentExpression { get; } public SyntaxToken OperatorToken { get; } [DiscardFromChildren] public NameExpressionSyntax MemberExpression { get; } public override SyntaxKind Kind => SyntaxKind.MemberAccessExpression; internal MemberAccessExpressionSyntax(SyntaxTree syntaxTree, - ExpressionSyntax parentExpression, + NameExpressionSyntax parentExpression, SyntaxToken operatorToken, NameExpressionSyntax memberExpression) : base(syntaxTree, memberExpression.IdentifierToken) From d48618dbfba7e470fb17bd04d56a3c61612094e1 Mon Sep 17 00:00:00 2001 From: Paulo Mattos Date: Wed, 23 Dec 2020 12:29:26 -0300 Subject: [PATCH 4/9] Corrige bind de tipos aninhados --- .../Syntax/Binding/BinderTests.cs | 55 ++++++++++++ src/Compiler/CodeAnalysis/Binding/Binder.cs | 84 +++++++++++++------ .../Binding/BoundCallExpression.cs | 3 +- .../Binding/BoundMemberExpression.cs | 4 +- .../BoundNestedTypeAccessExpression.cs | 23 +++++ .../CodeAnalysis/Binding/BoundNodeKind.cs | 1 + .../CodeAnalysis/Binding/BoundNodePrinter.cs | 9 ++ .../CodeAnalysis/Binding/BoundTreeRewriter.cs | 7 ++ 8 files changed, 159 insertions(+), 27 deletions(-) create mode 100644 src/Compiler/CodeAnalysis/Binding/BoundNestedTypeAccessExpression.cs diff --git a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs index faa151d..6afb58d 100644 --- a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs +++ b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs @@ -1420,6 +1420,35 @@ function main() AssertDiagnostics(text, diagnostics); } + [Fact] + public void Binder_MemberAccess_NestedType() + { + var text = @" + struct Line + { + var p1 : Point + var p2 : Point + + struct Point + { + var x : int + var y : int + } + } + + function main() + { + var line = Line() + line.p1.x = 10 + }"; + + var diagnostics = new List() + { + }; + + AssertDiagnostics(text, diagnostics); + } + /* [Fact] public void Binder_IfStatement_Reports_UnreachableCode_Warning() @@ -1530,6 +1559,32 @@ function a(x : string) } } + "; + + var diagnostics = new List() + { + }; + + AssertDiagnostics(text, diagnostics); + } + + + [Fact] + public void Binder_MemberAccess_SupportsOverloading() + { + var text = @" + struct TestStruct + { + function a(x : int) + { + a(string(x)) + } + + function a(x : string) + { + + } + } function main() { diff --git a/src/Compiler/CodeAnalysis/Binding/Binder.cs b/src/Compiler/CodeAnalysis/Binding/Binder.cs index 05b4ac0..bb0e833 100644 --- a/src/Compiler/CodeAnalysis/Binding/Binder.cs +++ b/src/Compiler/CodeAnalysis/Binding/Binder.cs @@ -869,46 +869,60 @@ private BoundExpression BindCallExpression(CallExpressionSyntax syntax, Function return new BoundErrorExpression(syntax); } + var receiverType = (_scope as TypeBoundScope)?.OwnerType; boundArguments = boundArgumentBuilder.ToImmutable(); - return new BoundCallExpression(syntax, function, boundArguments); + return new BoundCallExpression(syntax, function, receiverType, boundArguments); } private BoundExpression BindMemberAccessExpression(MemberAccessExpressionSyntax syntax) { var originalScope = _scope; - BoundExpression receiverExpression; - var stack = new Stack(); - ExpressionSyntax parent = syntax.ParentExpression; - - if (parent.Kind == SyntaxKind.MemberAccessExpression) + try { + var members = new Stack(); + var parent = syntax.ParentExpression; + + members.Push(syntax.MemberExpression); + while (parent is MemberAccessExpressionSyntax access) { - stack.Push(access.MemberExpression); + members.Push(access.MemberExpression); parent = access.ParentExpression; } - } - stack.Push((NameExpressionSyntax)parent); - do - { - // Advance the scope trough the nested access - var exp = stack.Pop(); - receiverExpression = BindNameExpression(exp); - Debug.Assert(receiverExpression.Type.BoundScope != null); - _scope = receiverExpression.Type.BoundScope; - } while (stack.Count > 0); - - var memberExpression = BindExpression(syntax.MemberExpression, true); + BoundExpression boundParent = BindNameExpression(parent, true); + BoundExpression receiverExpression; + _scope = boundParent.Type.BoundScope!; - // Return to the original binder scope - _scope = originalScope; + do + { + // Advance the scope trough the nested access + var exp = members.Pop(); + var boundMember = BindNameExpression(exp); - if (memberExpression.Kind == BoundNodeKind.ErrorExpression) + Debug.Assert(boundMember.Type.BoundScope != null); + _scope = boundMember.Type.BoundScope; + + if (boundMember.Kind == BoundNodeKind.ErrorExpression) + { + return boundMember; + } + else if (boundMember.Kind == BoundNodeKind.TypeReferenceExpression) + { + receiverExpression = new BoundNestedTypeAccessExpression(syntax, boundParent, (BoundTypeReferenceExpression)boundMember); + } + else + { + receiverExpression = new BoundMemberAccessExpression(syntax, boundParent, (BoundMemberExpression)boundMember); + } + boundParent = receiverExpression; + } while (members.Count > 0); + return receiverExpression; + } + finally { - return memberExpression; + _scope = originalScope; } - return new BoundMemberAccessExpression(syntax, receiverExpression, (BoundMemberExpression)memberExpression); } private BoundExpression BindConversion(ExpressionSyntax syntax, TypeSymbol type, bool allowExplicit = false) @@ -943,6 +957,18 @@ private BoundExpression BindConversion(TextLocation diagnosticLocation, BoundExp return new BoundConversionExpression(expression.Syntax, type, expression); } + private T? GetAncestorScope() where T : class, IBoundScope + { + var result = _scope as T; + var parent = _scope.Parent; + while (result == null && parent != null) + { + result = parent as T; + parent = parent.Parent; + } + return result; + } + private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byReference = false) { if (syntax.IdentifierToken.IsMissing) @@ -957,6 +983,11 @@ private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byR return BindSelfKeyword((SelfKeywordSyntax)syntax); } + if (syntax.Kind == SyntaxKind.CallExpression) + { + return BindCallExpression((CallExpressionSyntax)syntax); + } + var symbol = BindSymbolReference(syntax.IdentifierToken, syntax.IdentifierToken.Location); if (symbol == null) { @@ -972,7 +1003,10 @@ private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byR case SymbolKind.Member: - return new BoundMemberExpression(syntax, (MemberSymbol)symbol); + var receiverScope = GetAncestorScope(); + Debug.Assert(receiverScope != null); + var receiverType = receiverScope.OwnerType; + return new BoundMemberExpression(syntax, (MemberSymbol)symbol, receiverType); case SymbolKind.Type: case SymbolKind.Enum: diff --git a/src/Compiler/CodeAnalysis/Binding/BoundCallExpression.cs b/src/Compiler/CodeAnalysis/Binding/BoundCallExpression.cs index 680aeb3..55592df 100644 --- a/src/Compiler/CodeAnalysis/Binding/BoundCallExpression.cs +++ b/src/Compiler/CodeAnalysis/Binding/BoundCallExpression.cs @@ -11,8 +11,9 @@ internal class BoundCallExpression : BoundMemberExpression public BoundCallExpression(SyntaxNode syntax, FunctionSymbol function, + TypeSymbol? receiverType, ImmutableArray arguments) - : base(syntax, function) + : base(syntax, function, receiverType!) { Arguments = arguments; } diff --git a/src/Compiler/CodeAnalysis/Binding/BoundMemberExpression.cs b/src/Compiler/CodeAnalysis/Binding/BoundMemberExpression.cs index fcdbb22..f29dc04 100644 --- a/src/Compiler/CodeAnalysis/Binding/BoundMemberExpression.cs +++ b/src/Compiler/CodeAnalysis/Binding/BoundMemberExpression.cs @@ -5,15 +5,17 @@ namespace Compiler.CodeAnalysis.Binding { internal class BoundMemberExpression : BoundExpression { + public TypeSymbol ReceiverType { get; } public MemberSymbol Symbol { get; } public override TypeSymbol Type => Symbol.Type; public MemberKind MemberKind => Symbol.MemberKind; public override BoundNodeKind Kind => BoundNodeKind.MemberExpression; - public BoundMemberExpression(SyntaxNode syntax, MemberSymbol symbol) + public BoundMemberExpression(SyntaxNode syntax, MemberSymbol symbol, TypeSymbol receiverType) : base(syntax) { Symbol = symbol; + ReceiverType = receiverType; } } } \ No newline at end of file diff --git a/src/Compiler/CodeAnalysis/Binding/BoundNestedTypeAccessExpression.cs b/src/Compiler/CodeAnalysis/Binding/BoundNestedTypeAccessExpression.cs new file mode 100644 index 0000000..3f6935e --- /dev/null +++ b/src/Compiler/CodeAnalysis/Binding/BoundNestedTypeAccessExpression.cs @@ -0,0 +1,23 @@ +using Compiler.CodeAnalysis.Symbols; +using Compiler.CodeAnalysis.Syntax; + +namespace Compiler.CodeAnalysis.Binding +{ + internal class BoundNestedTypeAccessExpression : BoundExpression + { + public BoundExpression Instance { get; } + public BoundTypeReferenceExpression Member { get; } + public override TypeSymbol Type => Member.Type; + public override BoundNodeKind Kind => BoundNodeKind.NestedTypeAccessExpression; + + + public BoundNestedTypeAccessExpression(SyntaxNode syntax, + BoundExpression instance, + BoundTypeReferenceExpression member) + : base(syntax) + { + Instance = instance; + Member = member; + } + } +} \ No newline at end of file diff --git a/src/Compiler/CodeAnalysis/Binding/BoundNodeKind.cs b/src/Compiler/CodeAnalysis/Binding/BoundNodeKind.cs index cf6b2b1..7d08d69 100644 --- a/src/Compiler/CodeAnalysis/Binding/BoundNodeKind.cs +++ b/src/Compiler/CodeAnalysis/Binding/BoundNodeKind.cs @@ -31,5 +31,6 @@ public enum BoundNodeKind MemberAccessExpression, SelfExpression, MemberExpression, + NestedTypeAccessExpression, } } \ No newline at end of file diff --git a/src/Compiler/CodeAnalysis/Binding/BoundNodePrinter.cs b/src/Compiler/CodeAnalysis/Binding/BoundNodePrinter.cs index af537bc..9653a9b 100644 --- a/src/Compiler/CodeAnalysis/Binding/BoundNodePrinter.cs +++ b/src/Compiler/CodeAnalysis/Binding/BoundNodePrinter.cs @@ -104,11 +104,20 @@ public static void WriteTo(this BoundNode node, IndentedTextWriter writer) case BoundNodeKind.SelfExpression: WriteSelfExpression(writer); break; + case BoundNodeKind.NestedTypeAccessExpression: + WriteNestedTypeAccessExpression((BoundNestedTypeAccessExpression)node, writer); + break; default: throw new InvalidOperationException($"Unexpected node {node.Kind}"); } } + private static void WriteNestedTypeAccessExpression(BoundNestedTypeAccessExpression node, IndentedTextWriter writer) + { + node.Instance.WriteTo(writer); + node.Type.WriteTo(writer); + } + private static void WriteMemberExpression(BoundMemberExpression node, IndentedTextWriter writer) { node.Symbol.WriteTo(writer); diff --git a/src/Compiler/CodeAnalysis/Binding/BoundTreeRewriter.cs b/src/Compiler/CodeAnalysis/Binding/BoundTreeRewriter.cs index 035f5af..643302d 100644 --- a/src/Compiler/CodeAnalysis/Binding/BoundTreeRewriter.cs +++ b/src/Compiler/CodeAnalysis/Binding/BoundTreeRewriter.cs @@ -217,6 +217,8 @@ public BoundExpression RewriteExpression(BoundExpression expression) return RewriteTypeReferenceExpression((BoundTypeReferenceExpression)expression); case BoundNodeKind.MemberExpression: return RewriteMemberExpression((BoundMemberExpression)expression); + case BoundNodeKind.NestedTypeAccessExpression: + return RewriteNestedTypeAccessExpression((BoundNestedTypeAccessExpression)expression); default: throw new InvalidOperationException($"Unexpected expression {expression.Kind}."); } @@ -324,5 +326,10 @@ protected virtual BoundExpression RewriteMemberExpression(BoundMemberExpression { return node; } + + protected virtual BoundExpression RewriteNestedTypeAccessExpression(BoundNestedTypeAccessExpression node) + { + return node; + } } } \ No newline at end of file From a563476e042230c3d4b6037c186f1f9db69f7b72 Mon Sep 17 00:00:00 2001 From: Paulo Mattos Date: Wed, 23 Dec 2020 13:04:09 -0300 Subject: [PATCH 5/9] Adiciona suporte para acesso de tipos aninhados no emiter --- Samples/NestedType/NestedType.pys | 7 +- .../ConsoleOutputTests.cs | 12 +- src/Compiler/CodeAnalysis/Emit/Emitter.cs | 110 +++++++++++------- 3 files changed, 76 insertions(+), 53 deletions(-) diff --git a/Samples/NestedType/NestedType.pys b/Samples/NestedType/NestedType.pys index 5ce9e7a..02e3eff 100644 --- a/Samples/NestedType/NestedType.pys +++ b/Samples/NestedType/NestedType.pys @@ -14,15 +14,16 @@ struct Rect function main() { var rect = Rect() + //rect.p1 = Rect.Vector2Int() + rect.p1.x = 10 /* - rect.p1 = Rect.Point() - rect.p1.y = 10 rect.p2.x = 100 rect.p2.y = 100 -*/ + print(rect.p1.x) print(rect.p1.y) print(rect.p2.x) print(rect.p2.y) + //*/ } \ No newline at end of file diff --git a/src/Compiler.Tests.Samples/ConsoleOutputTests.cs b/src/Compiler.Tests.Samples/ConsoleOutputTests.cs index 2ee3ea3..646e5d4 100644 --- a/src/Compiler.Tests.Samples/ConsoleOutputTests.cs +++ b/src/Compiler.Tests.Samples/ConsoleOutputTests.cs @@ -21,13 +21,13 @@ public ConsoleOutputTests(ITestOutputHelper output) } [Theory] - [InlineData("HelloWorld", null)] - [InlineData("Evaluation")] - [InlineData("Input", "Paulo", "24")] - [InlineData("IsEven", "2", "10", "5")] - [InlineData("Enum")] + //[InlineData("HelloWorld", null)] + //[InlineData("Evaluation")] + //[InlineData("Input", "Paulo", "24")] + //[InlineData("IsEven", "2", "10", "5")] + //[InlineData("Enum")] [InlineData("Struct")] - // [InlineData("NestedType")] + [InlineData("NestedType")] public async Task SamplesTests(string filenamePrefix, params string[] inputs) { var psi = new ProcessStartInfo diff --git a/src/Compiler/CodeAnalysis/Emit/Emitter.cs b/src/Compiler/CodeAnalysis/Emit/Emitter.cs index e637c96..6ddef9b 100644 --- a/src/Compiler/CodeAnalysis/Emit/Emitter.cs +++ b/src/Compiler/CodeAnalysis/Emit/Emitter.cs @@ -711,11 +711,37 @@ private void EmitExpression(ILProcessor ilProcessor, BoundExpression node) EmitSelfExpression(ilProcessor); break; + case BoundNodeKind.MemberExpression: + EmitMemberExpression(ilProcessor, (BoundMemberExpression)node); + break; + default: throw new InvalidOperationException($"Unexpected node kind {node.Kind}"); } } + private void EmitMemberExpression(ILProcessor ilProcessor, BoundMemberExpression node) + { + Console.WriteLine($"EmitMemberExpression: {node}"); + Debug.Assert(node.ReceiverType != null); + var typeDefinition = Import(node.ReceiverType).Resolve(); + Debug.Assert(typeDefinition != null); + + switch (node.MemberKind) + { + case MemberKind.Field: + EmitFieldAccessExpression(ilProcessor, (FieldSymbol)node.Symbol, typeDefinition); + break; + + case MemberKind.Method: + EmitCallExpression(ilProcessor, (BoundCallExpression)node, typeDefinition); + break; + + default: + throw new InvalidOperationException($"Unexpected member type {node.MemberKind}"); + } + } + private static void EmitTypeReferenceExpression(ILProcessor ilProcessor, BoundTypeReferenceExpression node) { // HACK - This is not the rigth way to handle statics @@ -724,26 +750,38 @@ private static void EmitTypeReferenceExpression(ILProcessor ilProcessor, BoundTy private static void EmitConstantExpression(ILProcessor ilProcessor, BoundExpression node) { - Debug.Assert(node.ConstantValue != null); - if (node.Type == TypeSymbol.Bool) + EmitConstantExpression(ilProcessor, node.Type, node.ConstantValue); + } + + private static void EmitConstantExpression(ILProcessor ilProcessor, TypeSymbol type, BoundConstant? constant) + { + Debug.Assert(constant != null); + if (type == TypeSymbol.Bool) { - var value = (bool)node.ConstantValue.Value; + var value = (bool)constant.Value; var instruction = value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0; ilProcessor.Emit(instruction); } - else if (node.Type == TypeSymbol.Int) + else if (type == TypeSymbol.Int) { - var value = (int)node.ConstantValue.Value; + var value = (int)constant.Value; ilProcessor.Emit(OpCodes.Ldc_I4, value); } - else if (node.Type == TypeSymbol.String) + else if (type == TypeSymbol.String) { - var value = (string)node.ConstantValue.Value; + var value = (string)constant.Value; ilProcessor.Emit(OpCodes.Ldstr, value); } + /* + else if (type.IsEnum()) + { + var value = (int)constant.Value; + ilProcessor.Emit(OpCodes.Ldc_I4, value); + } + */ else { - throw new InvalidOperationException($"Unexpected constant expression type: {node.Type}"); + throw new InvalidOperationException($"Unexpected constant expression type: {type}"); } } @@ -982,7 +1020,7 @@ private void EmitBinaryExpression(ILProcessor ilProcessor, BoundBinaryExpression } } - private void EmitCallExpression(ILProcessor ilProcessor, BoundCallExpression node) + private void EmitCallExpression(ILProcessor ilProcessor, BoundCallExpression node, TypeDefinition? typeDefinition = null) { var function = (FunctionSymbol)node.Symbol; EmitExpressions(ilProcessor, node.Arguments); @@ -997,11 +1035,13 @@ private void EmitCallExpression(ILProcessor ilProcessor, BoundCallExpression nod } else if (node.Symbol.Name.Equals(".ctor")) { - var className = function.ReturnType.Name; - var structSymbol = _declaredTypes.First(s => s.Key.Name == className).Value; - + if (typeDefinition == null) + { + typeDefinition = Import(node.Symbol.Type).Resolve(); + } + Debug.Assert(typeDefinition != null); // TODO: We should use a general overload resolution algorithm instead - ilProcessor.Emit(OpCodes.Newobj, structSymbol.Methods[0]); + ilProcessor.Emit(OpCodes.Newobj, typeDefinition.Methods[0]); } else { @@ -1065,46 +1105,28 @@ private void EmitConversionExpression(ILProcessor ilProcessor, BoundConversionEx private void EmitMemberAccessExpression(ILProcessor ilProcessor, BoundMemberAccessExpression node) { - var typeDefinition = Import(node.Instance.Type).Resolve(); - Debug.Assert(typeDefinition != null); - - if (node.Instance.Kind == BoundNodeKind.SelfExpression) + if (node.Type.IsEnum()) { - EmitSelfExpression(ilProcessor); - } - else - { - EmitExpression(ilProcessor, node.Instance); + var field = (FieldSymbol)node.Member.Symbol; + EmitConstantExpression(ilProcessor, TypeSymbol.Int, field.Constant); + return; } - switch (node.Member.MemberKind) - { - case MemberKind.Field: - EmitFieldAccessExpression(ilProcessor, (FieldSymbol)node.Member.Symbol, typeDefinition); - break; - - case MemberKind.Method: - EmitCallExpression(ilProcessor, (BoundCallExpression)node.Member); - break; - - default: - throw new InvalidOperationException($"Unexpected member type {node.Member.MemberKind}"); - } + Console.WriteLine("EmitMemberAccessExpression"); + EmitExpression(ilProcessor, node.Instance); + EmitMemberExpression(ilProcessor, node.Member); } private static void EmitFieldAccessExpression(ILProcessor ilProcessor, FieldSymbol field, TypeDefinition typeDefinition) { - var fieldDefinition = GetField(field, typeDefinition); - Debug.Assert(fieldDefinition != null); - - if (fieldDefinition.Constant != null) + if (field.Constant != null) { - ilProcessor.Emit(OpCodes.Ldc_I4, (int)fieldDefinition.Constant); - } - else - { - ilProcessor.Emit(OpCodes.Ldfld, fieldDefinition); + EmitConstantExpression(ilProcessor, field.Type, field.Constant); } + + var fieldDefinition = GetField(field, typeDefinition); + Debug.Assert(fieldDefinition != null); + ilProcessor.Emit(OpCodes.Ldfld, fieldDefinition); } private static FieldDefinition? GetField(MemberSymbol member, TypeDefinition typeDefinition) From a52567560e2ac970fd50d350a06670a900f75785 Mon Sep 17 00:00:00 2001 From: Paulo Mattos Date: Thu, 24 Dec 2020 13:09:25 -0300 Subject: [PATCH 6/9] =?UTF-8?q?Corrige=20regress=C3=A3o=20no=20bind=20the?= =?UTF-8?q?=20membros=20sem=20o=20uso=20de=20self.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Syntax/Binding/BinderTests.cs | 18 +-- src/Compiler/CodeAnalysis/Binding/Binder.cs | 117 +++++++++++------- .../Binding/BoundCallExpression.cs | 3 +- .../Binding/BoundMemberExpression.cs | 4 +- .../Diagnostics/DiagnosticCode.cs | 2 - src/Compiler/CodeAnalysis/Emit/Emitter.cs | 10 +- .../CodeAnalysis/Symbols/FieldSymbol.cs | 13 +- .../CodeAnalysis/Symbols/FunctionSymbol.cs | 5 +- .../CodeAnalysis/Symbols/MemberSymbol.cs | 8 ++ 9 files changed, 106 insertions(+), 74 deletions(-) diff --git a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs index 6afb58d..160be0c 100644 --- a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs +++ b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs @@ -919,7 +919,7 @@ public void Binder_MultiLineComment_ReportsUnterminated() } [Fact] - public void Binder_Cannot_Access_Member() + public void Binder_MemberAccess_Reports_CannotAccessMember() { const string? text = @" function main() @@ -931,7 +931,7 @@ function main() "; var diagnostics = new List() { - DiagnosticCode.UndefinedName.GetDiagnostic("length"), + DiagnosticCode.CannotAccessMember.GetDiagnostic("length", "int"), DiagnosticCode.UndefinedFunction.GetDiagnostic("length"), }; AssertDiagnostics(text, diagnostics); @@ -1239,8 +1239,12 @@ struct TestStruct function f(i : int) { print(b) - print(self.a + 1) - print(i) + g() + } + + function g() + { + } } "; @@ -1276,7 +1280,7 @@ function f() AssertDiagnostics(text, diagnostics); } - + [Fact] public void Binder_SelfExpression_Reports_CannotUseSelfOutsideOfReceiverFunctions() { @@ -1313,13 +1317,13 @@ function f() : int function printTest(t : TestStruct) { - t.[f] = 10 + t.f [=] 10 } "; var diagnostics = new List() { - DiagnosticCode.NotAVariable.GetDiagnostic("f") + DiagnosticCode.CannotAssignMethod.GetDiagnostic("f", "TestStruct") }; AssertDiagnostics(text, diagnostics); diff --git a/src/Compiler/CodeAnalysis/Binding/Binder.cs b/src/Compiler/CodeAnalysis/Binding/Binder.cs index bb0e833..a18fa49 100644 --- a/src/Compiler/CodeAnalysis/Binding/Binder.cs +++ b/src/Compiler/CodeAnalysis/Binding/Binder.cs @@ -143,7 +143,7 @@ public static BoundProgram BindProgram(BoundGlobalScope globalScope) } Debug.Assert(function.BoundScope != null); - var binder = new Binder(function.BoundScope, function, function.Receiver); + var binder = new Binder(function.BoundScope, function, function.ReceiverType); var body = binder.BindStatement(function.Declaration!.Body); var loweredBody = Lowerer.Lower(function, body); @@ -217,11 +217,9 @@ private StructSymbol BindStructDeclaration(StructDeclarationSyntax syntax) private void BindMemberBlockStatement(MemberBlockStatementSyntax syntax, List functionsToLower) { - if (_scope is not TypeBoundScope typeScope) - { - throw new InvalidOperationException(); - } - + var typeScope = _scope as TypeBoundScope; + Debug.Assert(typeScope != null); + var type = typeScope.OwnerType; foreach (var statementSyntax in syntax.Statement.OfType()) { @@ -240,7 +238,7 @@ private void BindMemberBlockStatement(MemberBlockStatementSyntax syntax, List(); + Debug.Assert(typeScope?.OwnerType != null); + + var symbol = BindSymbolReference(syntax.IdentifierToken, false); + if (symbol == null) + { + Diagnostics.ReportCannotAccessMember(syntax.Location, typeScope.OwnerType.Name, syntax.IdentifierToken.Text); + return new BoundErrorExpression(syntax); + } + + switch (symbol.Kind) + { + case SymbolKind.Member: + case SymbolKind.Function: // TODO - HACK: Functions should be members + return new BoundMemberExpression(syntax, (MemberSymbol)symbol); + + case SymbolKind.Type: + case SymbolKind.Enum: + case SymbolKind.Struct: + return new BoundTypeReferenceExpression(syntax, (TypeSymbol)symbol); + + default: + throw new InvalidOperationException($"Unexpected symbol of kind {symbol.Kind}"); + } + } + + private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byReference = false, BoundExpression? boundParent = null) { if (syntax.IdentifierToken.IsMissing) { @@ -983,12 +1006,7 @@ private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byR return BindSelfKeyword((SelfKeywordSyntax)syntax); } - if (syntax.Kind == SyntaxKind.CallExpression) - { - return BindCallExpression((CallExpressionSyntax)syntax); - } - - var symbol = BindSymbolReference(syntax.IdentifierToken, syntax.IdentifierToken.Location); + var symbol = BindSymbolReference(syntax.IdentifierToken); if (symbol == null) { // No need to report an error @@ -1001,12 +1019,17 @@ private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byR case SymbolKind.Variable: return new BoundVariableExpression(syntax, (VariableSymbol)symbol, byReference); - case SymbolKind.Member: - var receiverScope = GetAncestorScope(); - Debug.Assert(receiverScope != null); - var receiverType = receiverScope.OwnerType; - return new BoundMemberExpression(syntax, (MemberSymbol)symbol, receiverType); + // If we get here, means an access to a member + // without the use of the SelfKeyword. + // So we synthesize a syntax with the self, + // and pass to the apropriate method + var keywordToken = new SyntaxToken(syntax.SyntaxTree, SyntaxKind.SelfKeyword, -1, SyntaxKind.SelfKeyword.GetText(), null, ImmutableArray.Empty, ImmutableArray.Empty); + var selfExpression = new SelfKeywordSyntax(syntax.SyntaxTree, keywordToken); + var dotToken = new SyntaxToken(syntax.SyntaxTree, SyntaxKind.DotToken, -1, SyntaxKind.DotToken.GetText(), null, ImmutableArray.Empty, ImmutableArray.Empty); + var accessSyntax = new MemberAccessExpressionSyntax(syntax.SyntaxTree, + selfExpression, dotToken, syntax); + return BindMemberAccessExpression(accessSyntax); case SymbolKind.Type: case SymbolKind.Enum: @@ -1027,13 +1050,13 @@ private BoundExpression BindSelfKeyword(SelfKeywordSyntax syntax) return new BoundErrorExpression(syntax); } - if (_function.Receiver == null) + if (_function.ReceiverType == null) { Diagnostics.ReportCannotUseSelfOutsideOfReceiverFunctions(syntax.IdentifierToken.Location, _function.Name); return new BoundErrorExpression(syntax); } - return new BoundSelfExpression(syntax, _function.Receiver); + return new BoundSelfExpression(syntax, _function.ReceiverType); } private TypeSymbol? LookupType(string name) diff --git a/src/Compiler/CodeAnalysis/Binding/BoundCallExpression.cs b/src/Compiler/CodeAnalysis/Binding/BoundCallExpression.cs index 55592df..680aeb3 100644 --- a/src/Compiler/CodeAnalysis/Binding/BoundCallExpression.cs +++ b/src/Compiler/CodeAnalysis/Binding/BoundCallExpression.cs @@ -11,9 +11,8 @@ internal class BoundCallExpression : BoundMemberExpression public BoundCallExpression(SyntaxNode syntax, FunctionSymbol function, - TypeSymbol? receiverType, ImmutableArray arguments) - : base(syntax, function, receiverType!) + : base(syntax, function) { Arguments = arguments; } diff --git a/src/Compiler/CodeAnalysis/Binding/BoundMemberExpression.cs b/src/Compiler/CodeAnalysis/Binding/BoundMemberExpression.cs index f29dc04..fcdbb22 100644 --- a/src/Compiler/CodeAnalysis/Binding/BoundMemberExpression.cs +++ b/src/Compiler/CodeAnalysis/Binding/BoundMemberExpression.cs @@ -5,17 +5,15 @@ namespace Compiler.CodeAnalysis.Binding { internal class BoundMemberExpression : BoundExpression { - public TypeSymbol ReceiverType { get; } public MemberSymbol Symbol { get; } public override TypeSymbol Type => Symbol.Type; public MemberKind MemberKind => Symbol.MemberKind; public override BoundNodeKind Kind => BoundNodeKind.MemberExpression; - public BoundMemberExpression(SyntaxNode syntax, MemberSymbol symbol, TypeSymbol receiverType) + public BoundMemberExpression(SyntaxNode syntax, MemberSymbol symbol) : base(syntax) { Symbol = symbol; - ReceiverType = receiverType; } } } \ No newline at end of file diff --git a/src/Compiler/CodeAnalysis/Diagnostics/DiagnosticCode.cs b/src/Compiler/CodeAnalysis/Diagnostics/DiagnosticCode.cs index 00c0beb..71da5bf 100644 --- a/src/Compiler/CodeAnalysis/Diagnostics/DiagnosticCode.cs +++ b/src/Compiler/CodeAnalysis/Diagnostics/DiagnosticCode.cs @@ -22,7 +22,6 @@ public enum DiagnosticCode UndefinedType, CannotConvertImplicitly, ParameterAlreadyDeclared, - FunctionsAreUnsupported, InvalidBreakOrContinue, InvalidReturnExpression, MissingReturnExpression, @@ -70,7 +69,6 @@ public static class DiagnosticCodeExtension {DiagnosticCode.UndefinedType, "Type '{0}' doesn't exist."}, {DiagnosticCode.CannotConvertImplicitly, "Cannot convert type '{0}' to '{1}'. An explicit conversion exists (are you missing a cast?)"}, {DiagnosticCode.ParameterAlreadyDeclared, "A parameter with the name '{0}' already exists."}, - {DiagnosticCode.FunctionsAreUnsupported, "Functions with return values are unsupported."}, {DiagnosticCode.InvalidBreakOrContinue, "The keyword '{0}' can only be used inside of loops."}, {DiagnosticCode.InvalidReturnExpression, "Since the function '{0}' does not return a value the 'return' keyword cannot be followed by an expression."}, {DiagnosticCode.MissingReturnExpression, "An expression of type '{0}' is expected."}, diff --git a/src/Compiler/CodeAnalysis/Emit/Emitter.cs b/src/Compiler/CodeAnalysis/Emit/Emitter.cs index 6ddef9b..c4199c1 100644 --- a/src/Compiler/CodeAnalysis/Emit/Emitter.cs +++ b/src/Compiler/CodeAnalysis/Emit/Emitter.cs @@ -375,7 +375,7 @@ private void EmitFunctionDeclarations(ImmutableDictionary Parameters { get; } public TypeSymbol ReturnType { get; } public FunctionDeclarationSyntax? Declaration { get; } - public TypeSymbol? Receiver { get; } public override SymbolKind Kind => SymbolKind.Function; public override MemberKind MemberKind => MemberKind.Method; @@ -36,14 +35,12 @@ internal FunctionSymbol(string name, FunctionDeclarationSyntax? declaration = null, IBoundScope? parentScope = null, TypeSymbol? receiver = null) - : base(declaration?.Identifier, name, true, false, type, null) + : base(declaration?.Identifier, name, true, false, receiver, type, null) { Parameters = parameters; ReturnType = type; Declaration = declaration; - Receiver = receiver; OverloadsBuilder = new List(); - if (parentScope!= null) { BoundScope = new FunctionBoundScope(receiver, this, parentScope); diff --git a/src/Compiler/CodeAnalysis/Symbols/MemberSymbol.cs b/src/Compiler/CodeAnalysis/Symbols/MemberSymbol.cs index 40467af..f390853 100644 --- a/src/Compiler/CodeAnalysis/Symbols/MemberSymbol.cs +++ b/src/Compiler/CodeAnalysis/Symbols/MemberSymbol.cs @@ -7,6 +7,12 @@ public abstract class MemberSymbol : TypedSymbol { public bool IsReadOnly { get; } public bool IsStatic { get; } + // TODO - HACK: + // Should not be nullable + // For now it's because functions can be global statements + // In the future they will only be valid inside classes/structs + // and this will be fixed + public TypeSymbol? ReceiverType { get; } public abstract MemberKind MemberKind { get; } public override SymbolKind Kind => SymbolKind.Member; @@ -14,12 +20,14 @@ private protected MemberSymbol(SyntaxNode? syntax, string name, bool isReadOnly, bool isStatic, + TypeSymbol? receiverType, TypeSymbol type, BoundConstant? constant) : base(syntax, name, type, isReadOnly ? constant : null) { IsReadOnly = isReadOnly; IsStatic = isStatic; + ReceiverType = receiverType; } } } \ No newline at end of file From 87203294f521fc5c690b6d48893e45845e7aa85c Mon Sep 17 00:00:00 2001 From: Paulo Mattos Date: Thu, 24 Dec 2020 13:28:30 -0300 Subject: [PATCH 7/9] =?UTF-8?q?Corrige=20execu=C3=A7=C3=A3o=20dos=20testes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Compiler.Tests.Samples/ConsoleOutputTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Compiler.Tests.Samples/ConsoleOutputTests.cs b/src/Compiler.Tests.Samples/ConsoleOutputTests.cs index 646e5d4..50e9ce0 100644 --- a/src/Compiler.Tests.Samples/ConsoleOutputTests.cs +++ b/src/Compiler.Tests.Samples/ConsoleOutputTests.cs @@ -21,13 +21,13 @@ public ConsoleOutputTests(ITestOutputHelper output) } [Theory] - //[InlineData("HelloWorld", null)] - //[InlineData("Evaluation")] - //[InlineData("Input", "Paulo", "24")] - //[InlineData("IsEven", "2", "10", "5")] - //[InlineData("Enum")] + [InlineData("HelloWorld", null)] + [InlineData("Evaluation")] + [InlineData("Input", "Paulo", "24")] + [InlineData("IsEven", "2", "10", "5")] + [InlineData("Enum")] [InlineData("Struct")] - [InlineData("NestedType")] + //[InlineData("NestedType")] public async Task SamplesTests(string filenamePrefix, params string[] inputs) { var psi = new ProcessStartInfo From 1614738af6b02dbbb53f67dfb4b7fcc1d9f2f347 Mon Sep 17 00:00:00 2001 From: Paulo Mattos Date: Thu, 24 Dec 2020 15:16:30 -0300 Subject: [PATCH 8/9] =?UTF-8?q?Corrige=20binder=20n=C3=A3o=20rodar=20caso?= =?UTF-8?q?=20um=20erro=20seja=20detectado=20no=20parser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Syntax/Binding/BinderTests.cs | 29 +++++++++++++++++-- src/Compiler/CodeAnalysis/Binding/Binder.cs | 29 +++---------------- src/Compiler/CodeAnalysis/Emit/Emitter.cs | 7 ----- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs index 160be0c..6c352db 100644 --- a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs +++ b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Compiler.CodeAnalysis; using Compiler.CodeAnalysis.Diagnostics; using Compiler.CodeAnalysis.Symbols; @@ -606,6 +605,30 @@ function main() }; AssertDiagnostics(text, diagnostics); } + + [Fact] + public void Binder_MemberAccess_Reports_UnexpectedToken() + { + var text = @" + struct TestStruct + { + } + + function main() + { + TestStruct. [=] 10 + TestStruct.[(][)] + } + "; + + var diagnostics = new List() + { + DiagnosticCode.UnexpectedToken.GetDiagnostic(SyntaxKind.EqualsToken, SyntaxKind.IdentifierToken), + DiagnosticCode.UnexpectedToken.GetDiagnostic(SyntaxKind.OpenParenthesisToken, SyntaxKind.IdentifierToken), + DiagnosticCode.UnexpectedToken.GetDiagnostic(SyntaxKind.CloseParenthesisToken, SyntaxKind.IdentifierToken) + }; + AssertDiagnostics(text, diagnostics); + } [Fact] public void Binder_NameExpression_Reports_NoErrorForInsertedToken() @@ -703,7 +726,7 @@ public void Binder_Parameter_Already_Declared() var text = @" function sum(a: int, b: int, [a: int]) : int { - return a + b + c + return a + b } "; diff --git a/src/Compiler/CodeAnalysis/Binding/Binder.cs b/src/Compiler/CodeAnalysis/Binding/Binder.cs index a18fa49..be9af2f 100644 --- a/src/Compiler/CodeAnalysis/Binding/Binder.cs +++ b/src/Compiler/CodeAnalysis/Binding/Binder.cs @@ -39,18 +39,8 @@ public static BoundGlobalScope BindGlobalScope(ImmutableArray syntax { var parentScope = CreateRootScope(); var binder = new Binder(parentScope, null, null); - binder.Diagnostics.AddRange(syntaxTrees.SelectMany(st => st.Diagnostics)); - if (binder.Diagnostics.HasErrors()) - { - return new BoundGlobalScope( - binder.Diagnostics.ToImmutableArray(), - null, - ImmutableArray.Empty, - ImmutableArray.Empty); - } - - + var typeDeclarations = syntaxTrees.SelectMany(st => st.Root.Members) .OfType(); @@ -113,13 +103,10 @@ private void BindTypeDeclaration(TypeDeclarationSyntax typeDeclarationSyntax) public static BoundProgram BindProgram(BoundGlobalScope globalScope) { - if (globalScope.Diagnostics.HasErrors()) - { - return EmptyProgram(globalScope); - } + var diagnostics = ImmutableArray.CreateBuilder(); + diagnostics.AddRange(globalScope.Diagnostics); var functionBodies = ImmutableDictionary.CreateBuilder(); - var diagnostics = ImmutableArray.CreateBuilder(); var functionsToLower = new List(globalScope.Functions.Where(f => f.Declaration != null)); @@ -162,14 +149,6 @@ public static BoundProgram BindProgram(BoundGlobalScope globalScope) globalScope.Types); } - private static BoundProgram EmptyProgram(BoundGlobalScope globalScope) - { - return new BoundProgram(globalScope.Diagnostics, - null, - ImmutableDictionary.Empty, - ImmutableArray.Empty); - } - private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax) { var parameters = ImmutableArray.CreateBuilder(); @@ -992,7 +971,7 @@ private BoundExpression BindMemberOrNestedTypeExpression(NameExpressionSyntax sy } } - private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byReference = false, BoundExpression? boundParent = null) + private BoundExpression BindNameExpression(NameExpressionSyntax syntax, bool byReference = false) { if (syntax.IdentifierToken.IsMissing) { diff --git a/src/Compiler/CodeAnalysis/Emit/Emitter.cs b/src/Compiler/CodeAnalysis/Emit/Emitter.cs index c4199c1..ec4a746 100644 --- a/src/Compiler/CodeAnalysis/Emit/Emitter.cs +++ b/src/Compiler/CodeAnalysis/Emit/Emitter.cs @@ -772,13 +772,6 @@ private static void EmitConstantExpression(ILProcessor ilProcessor, TypeSymbol t var value = (string)constant.Value; ilProcessor.Emit(OpCodes.Ldstr, value); } - /* - else if (type.IsEnum()) - { - var value = (int)constant.Value; - ilProcessor.Emit(OpCodes.Ldc_I4, value); - } - */ else { throw new InvalidOperationException($"Unexpected constant expression type: {type}"); From 6c08b3b5d73070e1f23b86ce11de939f5236ca8c Mon Sep 17 00:00:00 2001 From: Paulo Mattos Date: Thu, 24 Dec 2020 15:26:25 -0300 Subject: [PATCH 9/9] =?UTF-8?q?Simplifica=20c=C3=B3digo=20de=20Binder.GetA?= =?UTF-8?q?ncestorScope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Syntax/Binding/BinderTests.cs | 27 +++++++++++++++++++ src/Compiler/CodeAnalysis/Binding/Binder.cs | 16 ++--------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs index 6c352db..1d07e27 100644 --- a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs +++ b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs @@ -1118,6 +1118,33 @@ function main() AssertDiagnostics(text, diagnostics); } + [Fact] + public void Binder_MemberAccess_Nested_Reports_CannotAccessMember() + { + var text = @" + struct Point + { + } + + struct Line + { + var start: Point + } + + function main() + { + var nested = Line() + var x = nested.start.[x] + } + "; + + var diagnostics = new List() + { + DiagnosticCode.CannotAccessMember.GetDiagnostic("x", "Point"), + }; + AssertDiagnostics(text, diagnostics); + } + [Fact] public void Binder_MemberAccess_NestedCall() { diff --git a/src/Compiler/CodeAnalysis/Binding/Binder.cs b/src/Compiler/CodeAnalysis/Binding/Binder.cs index be9af2f..4552cda 100644 --- a/src/Compiler/CodeAnalysis/Binding/Binder.cs +++ b/src/Compiler/CodeAnalysis/Binding/Binder.cs @@ -921,18 +921,6 @@ private BoundExpression BindConversion(TextLocation diagnosticLocation, BoundExp return new BoundConversionExpression(expression.Syntax, type, expression); } - private T? GetAncestorScope() where T : class, IBoundScope - { - var result = _scope as T; - var parent = _scope.Parent; - while (result == null && parent != null) - { - result = parent as T; - parent = parent.Parent; - } - return result; - } - private BoundExpression BindMemberOrNestedTypeExpression(NameExpressionSyntax syntax) { if (syntax.IdentifierToken.IsMissing) @@ -945,8 +933,8 @@ private BoundExpression BindMemberOrNestedTypeExpression(NameExpressionSyntax sy return BindCallExpression((CallExpressionSyntax)syntax); } - var typeScope = GetAncestorScope(); - Debug.Assert(typeScope?.OwnerType != null); + var typeScope = _scope as TypeBoundScope; + Debug.Assert(typeScope != null); var symbol = BindSymbolReference(syntax.IdentifierToken, false); if (symbol == null)