From d03f781e3586c5da1b0a803960c7b9dc37949bcd Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Thu, 27 Jun 2024 00:38:29 +0300 Subject: [PATCH 1/7] catch generic behavior in return generation --- compiler/compilation/parts/bodies.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/compilation/parts/bodies.cs b/compiler/compilation/parts/bodies.cs index 876ff2df..10e20954 100644 --- a/compiler/compilation/parts/bodies.cs +++ b/compiler/compilation/parts/bodies.cs @@ -25,9 +25,11 @@ public void PostgenerateBody(MethodBuilder method) // VM needs the end-of-method notation, which is RETURN. // but in case of the VOID method, user may not write it // and i didnt think of anything smarter than checking last OpCode - if (!generator._opcodes.Any() && method.ReturnType.TypeCode == TYPE_VOID) + if (!generator._opcodes.Any() && method.ReturnType.IsGeneric) generator.Emit(OpCodes.RET); - if (generator._opcodes.Any() && generator._opcodes.Last() != OpCodes.RET.Value && method.ReturnType.TypeCode == TYPE_VOID) + if (!generator._opcodes.Any() && !method.ReturnType.IsGeneric && method.ReturnType.Class.TypeCode == TYPE_VOID) + generator.Emit(OpCodes.RET); + if (generator._opcodes.Any() && generator._opcodes.Last() != OpCodes.RET.Value && !method.ReturnType.IsGeneric && method.ReturnType.Class.TypeCode == TYPE_VOID) generator.Emit(OpCodes.RET); } From e6dcb140d008516aa2cd6d6a1e34f15b6f723f74 Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Thu, 27 Jun 2024 00:38:52 +0300 Subject: [PATCH 2/7] catch generic behavior in literals fields --- compiler/compilation/parts/fields.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/compilation/parts/fields.cs b/compiler/compilation/parts/fields.cs index 9d4383a5..3b698929 100644 --- a/compiler/compilation/parts/fields.cs +++ b/compiler/compilation/parts/fields.cs @@ -140,7 +140,7 @@ private FieldFlags GenerateFieldFlags(MemberDeclarationSyntax member) if (@override is not null && @override.Args.Any()) { var exp = @override.Args[0]; - if (exp is ArgumentExpression { Value: StringLiteralExpressionSyntax value }) + if (exp is { Value: StringLiteralExpressionSyntax value }) name = value.Value; else { @@ -171,9 +171,20 @@ public void GenerateField((VeinField field, FieldDeclarationSyntax member) t) // validate type compatible if (member.Field.Expression is LiteralExpressionSyntax literal) { + if (field.FieldType.IsGeneric) + { + Log.errors.Enqueue( + $"[red bold]Cannot implicitly convert generic type[/] " + + $"'[purple underline]{literal.GetTypeCode().AsClass()(Types.Storage).Name}[/]' to " + + $"'[purple underline]{field.FieldType.ToTemplateString()}[/]'.\n\t" + + $"at '[orange bold]{literal.Transform.pos.Line} line, {literal.Transform.pos.Column} column[/]' \n\t" + + $"in '[orange bold]{doc.FileEntity}[/]'."); + return; + } + if (literal is NumericLiteralExpressionSyntax numeric) { - if (!field.FieldType.TypeCode.CanImplicitlyCast(numeric)) + if (!field.FieldType.Class.TypeCode.CanImplicitlyCast(numeric)) { var diff_err = literal.Transform.DiffErrorFull(doc); @@ -184,13 +195,13 @@ public void GenerateField((VeinField field, FieldDeclarationSyntax member) t) Log.errors.Enqueue( $"[red bold]Cannot implicitly convert type[/] " + $"'[purple underline]{numeric.GetTypeCode().AsClass()(Types.Storage).Name}[/]' to " + - $"'[purple underline]{field.FieldType.Name}[/]'.\n\t" + + $"'[purple underline]{field.FieldType.ToTemplateString()}[/]'.\n\t" + $"at '[orange bold]{numeric.Transform.pos.Line} line, {numeric.Transform.pos.Column} column[/]' \n\t" + $"in '[orange bold]{doc.FileEntity}[/]'." + $"{diff_err}"); } } - else if (literal.GetTypeCode() != field.FieldType.TypeCode) + else if (literal.GetTypeCode() != field.FieldType.Class.TypeCode) { var diff_err = literal.Transform.DiffErrorFull(doc); Log.errors.Enqueue( From ef79663d74ae1f9bd3afa0345319d11abe5deb31 Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Thu, 27 Jun 2024 00:39:34 +0300 Subject: [PATCH 3/7] use generic complex type in fields and return types method --- .../ConvertNotSupportedException.cs | 3 +- runtime/common/reflection/VeinArgumentRef.cs | 18 ++---------- runtime/common/reflection/VeinField.cs | 16 +++++----- runtime/common/reflection/VeinMethod.cs | 17 ++++------- runtime/ishtar.base/emit/ClassBuilder.cs | 7 ++--- runtime/ishtar.base/emit/MethodBuilder.cs | 4 +-- runtime/ishtar.base/emit/ModuleReader.cs | 19 +++++++----- .../runtime/vm/RuntimeIshtarClass.cs | 7 +++-- .../runtime/vm/RuntimeIshtarField.cs | 13 ++++++--- .../runtime/vm/RuntimeIshtarModule.cs | 29 +++++++++---------- 10 files changed, 63 insertions(+), 70 deletions(-) diff --git a/runtime/common/exceptions/ConvertNotSupportedException.cs b/runtime/common/exceptions/ConvertNotSupportedException.cs index 0ab57c20..497e831a 100644 --- a/runtime/common/exceptions/ConvertNotSupportedException.cs +++ b/runtime/common/exceptions/ConvertNotSupportedException.cs @@ -9,6 +9,7 @@ public ConvertNotSupportedException(VeinTypeCode typeCode) : base($"Cannot get converted, '{typeCode}' is not supported.") { } public ConvertNotSupportedException(VeinField field) - : base($"Cannot get converted, '{field.FullName}' with '{field.FieldType.FullName.NameWithNS}' type is not supported.") { } + : base( + $"Cannot get converted, '{field.FullName}' with '{field.FieldType.ToTemplateString()}' type is not supported.") { } } } diff --git a/runtime/common/reflection/VeinArgumentRef.cs b/runtime/common/reflection/VeinArgumentRef.cs index d7985360..0d400da8 100644 --- a/runtime/common/reflection/VeinArgumentRef.cs +++ b/runtime/common/reflection/VeinArgumentRef.cs @@ -2,12 +2,12 @@ namespace vein.runtime; #nullable enable using System; -public class VeinArgumentRef +public class VeinArgumentRef(string name, VeinComplexType complexType) { public const string THIS_ARGUMENT = ""; - public VeinComplexType ComplexType { get; private set; } - public string Name { get; } + public VeinComplexType ComplexType { get; private set; } = complexType; + public string Name { get; } = name; public void Temp_ReplaceType(VeinClass @class) @@ -23,18 +23,6 @@ public void Temp_ReplaceType(VeinClass @class) public bool IsGeneric => ComplexType.IsGeneric; - public VeinArgumentRef(string name, VeinClass clazz) - { - Name = name; - ComplexType = clazz; - } - - public VeinArgumentRef(string name, VeinTypeArg typeArg) - { - Name = name; - ComplexType = typeArg; - } - public string ToTemplateString() => ComplexType!.ToTemplateString(); diff --git a/runtime/common/reflection/VeinField.cs b/runtime/common/reflection/VeinField.cs index 9884bd10..81579268 100644 --- a/runtime/common/reflection/VeinField.cs +++ b/runtime/common/reflection/VeinField.cs @@ -42,11 +42,11 @@ public static FieldName Resolve(int index, VeinModule module) public override string ToString() => $"{Class}.{Name}"; } - public class VeinProperty(VeinClass owner, FieldName fullName, FieldFlags flags, VeinClass propType) + public class VeinProperty(VeinClass owner, FieldName fullName, FieldFlags flags, VeinComplexType propType) : VeinMember, IAspectable { public FieldName FullName { get; protected internal set; } = fullName; - public VeinClass PropType { get; set; } = propType; + public VeinComplexType PropType { get; set; } = propType; public FieldFlags Flags { get; set; } = flags; public VeinClass Owner { get; set; } = owner; public List Aspects { get; } = new(); @@ -113,8 +113,8 @@ public static VeinProperty RestoreFrom(string name, VeinClass clazz) ShadowField = shadowField }; - var setterArgs = shadowField.IsStatic ? Array.Empty() : [clazz]; - var getterArgs = shadowField.IsStatic ? [shadowField.FieldType] : new[] { clazz, shadowField.FieldType }; + var setterArgs = shadowField.IsStatic ? Array.Empty() : [clazz]; + var getterArgs = shadowField.IsStatic ? [shadowField.FieldType] : new[] { (VeinComplexType)clazz, shadowField.FieldType }; var getMethod = clazz.FindMethod(GetterFnName(name), setterArgs, true); @@ -130,11 +130,11 @@ public static VeinProperty RestoreFrom(string name, VeinClass clazz) } } - public class VeinField(VeinClass owner, FieldName fullName, FieldFlags flags, VeinClass fieldType) + public class VeinField(VeinClass owner, FieldName fullName, FieldFlags flags, VeinComplexType fieldType) : VeinMember, IAspectable { public FieldName FullName { get; protected internal set; } = fullName; - public VeinClass FieldType { get; set; } = fieldType; + public VeinComplexType FieldType { get; set; } = fieldType; public FieldFlags Flags { get; set; } = flags; public VeinClass Owner { get; set; } = owner; public List Aspects { get; } = new(); @@ -195,9 +195,11 @@ private static Func WrapConverter(Func actor, Ve public static Func GetConverter(this VeinField field) { + if (field.FieldType.IsGeneric) + throw new ConvertNotSupportedException(field); // generic not support convert try { - return GetConverter(field.FieldType.TypeCode); + return GetConverter(field.FieldType.Class.TypeCode); } catch (NotSupportedException) { diff --git a/runtime/common/reflection/VeinMethod.cs b/runtime/common/reflection/VeinMethod.cs index 3db16575..325f6680 100644 --- a/runtime/common/reflection/VeinMethod.cs +++ b/runtime/common/reflection/VeinMethod.cs @@ -65,7 +65,7 @@ public record VeinMethodSignature( public class VeinMethod : VeinMember, IAspectable { public VeinMethodSignature Signature { get; private set; } - public VeinClass ReturnType => Signature.ReturnType; + public VeinComplexType ReturnType => Signature.ReturnType; public VeinClass Owner { get; protected internal set; } public Dictionary Locals { get; } = new(); public List Aspects { get; } = new(); @@ -74,15 +74,7 @@ public class VeinMethod : VeinMember, IAspectable public void Temp_ReplaceReturnType(VeinClass clazz) => Signature = Signature with { ReturnType = clazz }; - internal VeinMethod(string name, MethodFlags flags, VeinClass returnType, VeinClass owner, params VeinArgumentRef[] args) - { - Owner = owner; - Flags = flags; - Signature = new VeinMethodSignature(returnType, args); - Name = RegenerateName(name); - } - - internal VeinMethod(string name, MethodFlags flags, VeinTypeArg returnType, VeinClass owner, params VeinArgumentRef[] args) + internal VeinMethod(string name, MethodFlags flags, VeinComplexType returnType, VeinClass owner, params VeinArgumentRef[] args) { Owner = owner; Flags = flags; @@ -97,7 +89,10 @@ private string RegenerateName(string n) => public static string GetFullName(string name, VeinComplexType returnType, IEnumerable args) => $"{name}{new VeinMethodSignature(returnType, args.ToList()).ToTemplateString()}"; - + + public static string GetFullName(string name, VeinComplexType returnType, IEnumerable args) + => $"{name}{new VeinMethodSignature(returnType, args.Select((x, y) => new VeinArgumentRef(y.ToString(), x)).ToList()).ToTemplateString()}"; + public static string GetFullName(string name, VeinComplexType returnType, IEnumerable args) => $"{name}{new VeinMethodSignature(returnType, args.Select((x, y) => new VeinArgumentRef(y.ToString(), x)).ToList()).ToTemplateString()}"; diff --git a/runtime/ishtar.base/emit/ClassBuilder.cs b/runtime/ishtar.base/emit/ClassBuilder.cs index ec752a0d..63dff6c0 100644 --- a/runtime/ishtar.base/emit/ClassBuilder.cs +++ b/runtime/ishtar.base/emit/ClassBuilder.cs @@ -195,7 +195,7 @@ byte[] IBaker.BakeByteArray() foreach (var field in Fields) { binary.Write(moduleBuilder.InternFieldName(field.FullName)); - binary.WriteTypeName(field.FieldType.FullName, moduleBuilder); + binary.WriteComplexType(field.FieldType, moduleBuilder); binary.Write((short)field.Flags); } return mem.ToArray(); @@ -214,7 +214,7 @@ string IBaker.BakeDebugString() foreach (var field in Fields) { var flags = field.Flags.EnumerateFlags(new [] {FieldFlags.None}).Join(' ').ToLowerInvariant(); - str.AppendLine($"\t.field '{field.Name}' as '{field.FieldType.Name}' {flags}"); + str.AppendLine($"\t.field '{field.Name}' as '{field.FieldType.ToTemplateString()}' {flags}"); } foreach (var method in Methods.OfType().Select(method => method.BakeDebugString())) str.AppendLine($"{method.Split("\n").Select(x => $"\t{x}").Join("\n").TrimEnd('\n')}"); @@ -236,8 +236,7 @@ protected override VeinMethod GetOrCreateTor(string name, bool isStatic = false) flags |= MethodFlags.Static; var returnType = isStatic ? VeinTypeCode.TYPE_VOID.AsClass(moduleBuilder) : this; - var args = isStatic || name == "dtor" ? new VeinArgumentRef[0] : - new VeinArgumentRef[1] { new VeinArgumentRef(VeinArgumentRef.THIS_ARGUMENT, this) }; + var args = isStatic || name == "dtor" ? Array.Empty() : [new VeinArgumentRef(VeinArgumentRef.THIS_ARGUMENT, this)]; ctor = DefineMethod(name, flags, returnType, args); moduleBuilder.InternString(ctor.Name); diff --git a/runtime/ishtar.base/emit/MethodBuilder.cs b/runtime/ishtar.base/emit/MethodBuilder.cs index 254bde6a..bf3ab736 100644 --- a/runtime/ishtar.base/emit/MethodBuilder.cs +++ b/runtime/ishtar.base/emit/MethodBuilder.cs @@ -44,7 +44,7 @@ public byte[] BakeByteArray() binary.Write(0); // body size binary.Write((byte)0); // stack size binary.Write((byte)0); // locals size - binary.WriteTypeName(ReturnType.FullName, moduleBuilder); + binary.WriteComplexType(ReturnType, moduleBuilder); binary.WriteArguments(Signature, moduleBuilder); binary.Write(Array.Empty()); // IL Body return mem.ToArray(); @@ -57,7 +57,7 @@ public byte[] BakeByteArray() binary.Write(body.Length); // body size binary.Write(_generator.GetStackSize()); binary.Write((byte)_generator.LocalsSize); // locals size - binary.WriteTypeName(ReturnType.FullName, moduleBuilder); + binary.WriteComplexType(ReturnType, moduleBuilder); binary.WriteArguments(Signature, moduleBuilder); binary.Write(body); // IL Body diff --git a/runtime/ishtar.base/emit/ModuleReader.cs b/runtime/ishtar.base/emit/ModuleReader.cs index 05adedc7..692aa20e 100644 --- a/runtime/ishtar.base/emit/ModuleReader.cs +++ b/runtime/ishtar.base/emit/ModuleReader.cs @@ -286,9 +286,11 @@ public static ModuleReader Read(byte[] arr, IReadOnlyList deps, Func { foreach (var method in @class.Methods) { - if (method.ReturnType is not UnresolvedVeinClass) + if (method.ReturnType.IsGeneric) continue; - method.Temp_ReplaceReturnType(module.FindType(method.ReturnType.FullName, true)); + if (method.ReturnType.Class is not UnresolvedVeinClass) + continue; + method.Temp_ReplaceReturnType(module.FindType(method.ReturnType.Class.FullName, true)); } foreach (var method in @class.Methods) @@ -304,9 +306,11 @@ public static ModuleReader Read(byte[] arr, IReadOnlyList deps, Func } foreach (var field in @class.Fields) { - if (field.FieldType is not UnresolvedVeinClass) + if (field.FieldType.IsGeneric) + continue; + if (field.FieldType.Class is not UnresolvedVeinClass) continue; - field.FieldType = module.FindType(field.FieldType.FullName, true); + field.FieldType = module.FindType(field.FieldType.Class.FullName, true); } } @@ -400,8 +404,7 @@ public static void DecodeField(BinaryReader binary, VeinClass @class, ModuleRead foreach (var _ in ..binary.ReadInt32()) { var name = FieldName.Resolve(binary.ReadInt32(), module); - var type_name = binary.ReadTypeName(module); - var type = module.FindType(type_name, true, false); + var type = binary.ReadComplexType(module); var flags = (FieldFlags) binary.ReadInt16(); var method = new VeinField(@class, name, flags, type); @class.Fields.Add(method); @@ -417,11 +420,11 @@ public static VeinMethod DecodeMethod(byte[] arr, VeinClass @class, ModuleReader var bodysize = binary.ReadInt32(); var stacksize = binary.ReadByte(); var locals = binary.ReadByte(); - var retType = binary.ReadTypeName(module); + var retType = binary.ReadComplexType(module); var args = ReadArguments(binary, module); var _ = binary.ReadBytes(bodysize); return new VeinMethod(module.GetConstStringByIndex(idx), flags, - module.FindType(retType, true, false), + retType, @class, args.ToArray()); } diff --git a/runtime/ishtar.vm/runtime/vm/RuntimeIshtarClass.cs b/runtime/ishtar.vm/runtime/vm/RuntimeIshtarClass.cs index ac438d8b..5480e1bd 100644 --- a/runtime/ishtar.vm/runtime/vm/RuntimeIshtarClass.cs +++ b/runtime/ishtar.vm/runtime/vm/RuntimeIshtarClass.cs @@ -153,7 +153,7 @@ internal void ReplaceParent(RuntimeIshtarClass* parent) return f; } - internal RuntimeIshtarField* DefineField(RuntimeFieldName* name, FieldFlags flags, RuntimeIshtarClass* type) + internal RuntimeIshtarField* DefineField(RuntimeFieldName* name, FieldFlags flags, RuntimeComplexType type) { var exist = Fields->FirstOrNull(x => x->Name.Equals(name->Name)); @@ -413,7 +413,10 @@ public void init_vtable(VirtualMachine vm, CallFrame* fr = null) #if DEBUG_VTABLE - dvtable.vtable_info[vtable_offset] = $"DEFAULT_VALUE OF [{field->FullName->ToString()}::{field->FieldType->Name}]"; + if (field->FieldType.IsGeneric) + dvtable.vtable_info[vtable_offset] = $"DEFAULT_VALUE OF [{field->FullName->ToString()}::{StringStorage.GetStringUnsafe(field->FieldType.TypeArg->Name)}]"; + else + dvtable.vtable_info[vtable_offset] = $"DEFAULT_VALUE OF [{field->FullName->ToString()}::{field->FieldType.Class->FullName->ToString()}]"; dvtable.vtable_fields[vtable_offset] = field; #endif diff --git a/runtime/ishtar.vm/runtime/vm/RuntimeIshtarField.cs b/runtime/ishtar.vm/runtime/vm/RuntimeIshtarField.cs index f891e265..29405c03 100644 --- a/runtime/ishtar.vm/runtime/vm/RuntimeIshtarField.cs +++ b/runtime/ishtar.vm/runtime/vm/RuntimeIshtarField.cs @@ -22,7 +22,7 @@ public readonly unsafe struct WeakRef(void* ptr) where T : class public unsafe struct RuntimeIshtarField : IEq, IDisposable { public RuntimeIshtarClass* Owner { get; private set; } - public RuntimeIshtarClass* FieldType { get; private set; } + public RuntimeComplexType FieldType { get; private set; } public string Name => FullName->Name; public ulong vtable_offset; @@ -38,7 +38,7 @@ public void Dispose() VirtualMachine.GlobalPrintln($"Disposed field '{Name}'"); FullName = null; - FieldType = null; + FieldType = default; Owner = null; default_value = null; _selfRef = null; @@ -57,7 +57,7 @@ public void Dispose() public RuntimeIshtarField(RuntimeIshtarClass* owner, RuntimeFieldName* fullName, FieldFlags flags, - RuntimeIshtarClass* fieldType, + RuntimeComplexType fieldType, RuntimeIshtarField* selfRef) { Owner = owner; @@ -124,6 +124,11 @@ bool failMapping(int code, RuntimeIshtarField* field) public static bool Eq(RuntimeIshtarField* p1, RuntimeIshtarField* p2) => p1->Name.Equals(p2->Name) && p1->Flags == p2->Flags && RuntimeIshtarClass.Eq(p1->FieldType, p2->FieldType); - public override string ToString() => $"Field '{FullName->Name}': '{FieldType->FullName->NameWithNS}'"; + public override string ToString() + { + if (FieldType.IsGeneric) + return $"Field '{FullName->Name}': '{StringStorage.GetStringUnsafe(FieldType.TypeArg->Name)}'"; + return $"Field '{FullName->Name}': '{FieldType.Class->FullName->ToString()}'"; + } } } diff --git a/runtime/ishtar.vm/runtime/vm/RuntimeIshtarModule.cs b/runtime/ishtar.vm/runtime/vm/RuntimeIshtarModule.cs index 3cbf1c0b..3b628ffc 100644 --- a/runtime/ishtar.vm/runtime/vm/RuntimeIshtarModule.cs +++ b/runtime/ishtar.vm/runtime/vm/RuntimeIshtarModule.cs @@ -449,11 +449,14 @@ public string Name }); @class->Fields->ForEach(field => { - if (!field->FieldType->IsUnresolved) + if (field->FieldType.IsGeneric) return; - VirtualMachine.GlobalPrintln($"resolve field.type[]: [{field->FieldType->FullName->NameWithNS}] "); - field->ReplaceType(module->FindType(field->FieldType->FullName, true, true)); + if (!field->FieldType.Class->IsUnresolved) + return; + VirtualMachine.GlobalPrintln($"resolve field.type[]: [{field->FieldType.Class->FullName->ToString()}] "); + + field->ReplaceType(module->FindType(field->FieldType.Class->FullName, true, true)); }); }); @@ -472,8 +475,7 @@ public string Name foreach (var bodyField in body.Fields) { - var field = clazz->DefineField(bodyField.FieldName, bodyField.Flags, - module->FindType(bodyField.FieldType, true, true)); + var field = clazz->DefineField(bodyField.FieldName, bodyField.Flags, bodyField.FieldType); VirtualMachine.GlobalPrintln($"constructed field: [{field->Name} at {field->Owner->FullName->NameWithNS}] "); } @@ -703,10 +705,10 @@ public class DeferClassBodyData(RuntimeIshtarClass* clazz, List methods, public List Fields { get; } = fields; } - public class DeferClassFieldData(RuntimeFieldName* fieldName, RuntimeQualityTypeName* fieldType, FieldFlags flags) + public class DeferClassFieldData(RuntimeFieldName* fieldName, RuntimeComplexType fieldType, FieldFlags flags) { public RuntimeFieldName* FieldName { get; } = fieldName; - public RuntimeQualityTypeName* FieldType { get; } = fieldType; + public RuntimeComplexType FieldType { get; } = fieldType; public FieldFlags Flags { get; } = flags; } @@ -716,13 +718,10 @@ public List DecodeField(BinaryReader binary, RuntimeIshtarC foreach (var _ in ..binary.ReadInt32()) { var name = RuntimeFieldName.Resolve(binary.ReadInt32(), ishtarModule); - var type_name = binary.ReadTypeName(ishtarModule); - //var type = ishtarModule->FindType(type_name, true, false); + var type = binary.ReadComplexType(ishtarModule); var flags = (FieldFlags) binary.ReadInt16(); - lst.Add(new DeferClassFieldData(name, type_name, flags)); - - //@class->DefineField(name, flags, type); + lst.Add(new DeferClassFieldData(name, type, flags)); } return lst; @@ -740,13 +739,11 @@ public List DecodeField(BinaryReader binary, RuntimeIshtarC var bodysize = binary.ReadInt32(); var stacksize = binary.ReadByte(); var locals = binary.ReadByte(); - var retType = binary.ReadTypeName(ishtarModule); + var retType = binary.ReadComplexType(ishtarModule); var args = ReadArguments(binary, ishtarModule); var body = binary.ReadBytes(bodysize); - var returnType = ishtarModule->FindType(retType, true, false); - - var mth = @class->DefineMethod(methodName, returnType, flags, args); + var mth = @class->DefineMethod(methodName, retType, flags, args); if (mth->IsExtern) return mth; From 4b975ff52d4f0e440be2bb05c158e6b77e223ab5 Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Thu, 27 Jun 2024 00:39:47 +0300 Subject: [PATCH 4/7] use ComplexType in ResolveScopedIdentifierType --- runtime/ishtar.generator/GeneratorContext.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/runtime/ishtar.generator/GeneratorContext.cs b/runtime/ishtar.generator/GeneratorContext.cs index 4de9a207..0bdfc584 100644 --- a/runtime/ishtar.generator/GeneratorContext.cs +++ b/runtime/ishtar.generator/GeneratorContext.cs @@ -110,12 +110,15 @@ public ClassBuilder CreateHiddenType(string name) this.LogError($"Argument '{id}' is not found in '{this.CurrentMethod.Name}' function.", id); throw new SkipStatementException(); } - public VeinClass ResolveScopedIdentifierType(IdentifierExpression id) + public VeinComplexType ResolveScopedIdentifierType(IdentifierExpression id) { if (ResolveArgument(id) is not null) { - var a = ResolveArgument(id); - return a.Value.Item1.Type; + var (arg, index) = ResolveArgument(id)!.Value; + + if (arg.IsGeneric) + return arg.TypeArg; + return arg.Type; } if (CurrentScope.HasVariable(id)) return CurrentScope.GetVariable(id).@class; From 52e6993ceb09234f1b333e7cfccef82593b13958 Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Thu, 27 Jun 2024 00:40:15 +0300 Subject: [PATCH 5/7] catch generic behavior in multiple expressions --- runtime/ishtar.generator/generators/cycles.cs | 17 ++++++++++++-- runtime/ishtar.generator/generators/logic.cs | 8 ++++++- .../ishtar.generator/generators/operators.cs | 21 ++++++++++++++--- runtime/ishtar.generator/generators/types.cs | 23 ++++++++++++------- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/runtime/ishtar.generator/generators/cycles.cs b/runtime/ishtar.generator/generators/cycles.cs index f08e92a7..be545a8e 100644 --- a/runtime/ishtar.generator/generators/cycles.cs +++ b/runtime/ishtar.generator/generators/cycles.cs @@ -14,7 +14,14 @@ public static void EmitWhileStatement(this ILGenerator gen, WhileStatementSyntax var end = gen.DefineLabel("while-end"); var expType = @while.Expression.DetermineType(ctx); gen.UseLabel(start); - if (expType.TypeCode == VeinTypeCode.TYPE_BOOLEAN) + + if (expType.IsGeneric) // todo implicit boolean and generics + { + ctx.LogError($"Cannot implicitly convert generic type '{expType}' to 'Boolean'", @while.Expression); + return; + } + + if (expType.Class.TypeCode == VeinTypeCode.TYPE_BOOLEAN) { gen.EmitExpression(@while.Expression); gen.Emit(OpCodes.JMP_F, end); @@ -44,7 +51,13 @@ public static void EmitForStatement(this ILGenerator gen, ForStatementSyntax @fo { var expType = @for.LoopContact.DetermineType(ctx); - if (expType.TypeCode is not VeinTypeCode.TYPE_BOOLEAN) + if (expType.IsGeneric) + { + ctx.LogError($"Cannot implicitly convert generic type '{expType}' to 'Boolean'", @for.LoopContact); + return; // TODO implicit boolean + } + + if (expType.Class.TypeCode is not VeinTypeCode.TYPE_BOOLEAN) { ctx.LogError($"Cannot implicitly convert type '{expType}' to 'Boolean'", @for.LoopContact); return; // TODO implicit boolean diff --git a/runtime/ishtar.generator/generators/logic.cs b/runtime/ishtar.generator/generators/logic.cs index 43d97562..62f533e0 100644 --- a/runtime/ishtar.generator/generators/logic.cs +++ b/runtime/ishtar.generator/generators/logic.cs @@ -14,6 +14,12 @@ public static void EmitIfElse(this ILGenerator generator, IfStatementSyntax ifSt var ctx = generator.ConsumeFromMetadata("context"); var expType = ifStatement.Expression.DetermineType(ctx); + if (expType.IsGeneric) + { + ctx.LogError($"Cannot implicitly convert generic type '{expType.ToTemplateString()}' to 'Boolean'", ifStatement.Expression); + return; + } + if (!ctx.DisableOptimization && ifStatement.Expression is BoolLiteralExpressionSyntax @bool) { if (@bool.Value) @@ -25,7 +31,7 @@ public static void EmitIfElse(this ILGenerator generator, IfStatementSyntax ifSt else generator.Emit(OpCodes.JMP, elseLabel); } - else if (expType.TypeCode == VeinTypeCode.TYPE_BOOLEAN) + else if (expType.Class.TypeCode == VeinTypeCode.TYPE_BOOLEAN) { generator.EmitExpression(ifStatement.Expression); generator.Emit(OpCodes.JMP_F, elseLabel); diff --git a/runtime/ishtar.generator/generators/operators.cs b/runtime/ishtar.generator/generators/operators.cs index 9d61e232..0f5a4e58 100644 --- a/runtime/ishtar.generator/generators/operators.cs +++ b/runtime/ishtar.generator/generators/operators.cs @@ -30,15 +30,30 @@ public static void EmitBinaryExpression(this ILGenerator gen, BinaryExpressionSy gen.EmitExpression(right); gen.EmitExpression(left); - var left_type = left.DetermineType(context); - var right_type = right.DetermineType(context); + var left_type_u = left.DetermineType(context); + var right_type_u = right.DetermineType(context); + + + if (left_type_u.IsGeneric) + { + context.LogError($"Cannot implicitly convert type '{left_type_u.TypeArg.Name}' to 'Number'", left); + return; + } + if (right_type_u.IsGeneric) + { + context.LogError($"Cannot implicitly convert type '{right_type_u.TypeArg.Name}' to 'Number'", right); + return; + } + + var left_type = left_type_u.Class; + var right_type = right_type_u.Class; if (left_type.TypeCode.HasNumber() && right_type.TypeCode.HasNumber()) gen.EmitBinaryOperator(op); else { var name = $"op_{op}"; - var args = new[] { left_type, right_type }; + var args = new[] { (VeinComplexType)left_type, (VeinComplexType)right_type }; var method = left_type.FindMethod(name, args); diff --git a/runtime/ishtar.generator/generators/types.cs b/runtime/ishtar.generator/generators/types.cs index b8bf69b1..f3c5704c 100644 --- a/runtime/ishtar.generator/generators/types.cs +++ b/runtime/ishtar.generator/generators/types.cs @@ -51,9 +51,9 @@ public static VeinTypeCode GetTypeCodeFromNumber(NumericLiteralExpressionSyntax _ => throw new NotSupportedException($"{number} is not support number.") }; - public static VeinClass ResolveMemberType(this IEnumerable chain, GeneratorContext context) + public static VeinComplexType ResolveMemberType(this IEnumerable chain, GeneratorContext context) { - var t = default(VeinClass); + var t = default(VeinComplexType); var prev_id = default(IdentifierExpression); using var enumerator = chain.GetEnumerator(); @@ -82,10 +82,17 @@ public static VeinClass ResolveMemberType(this IEnumerable cha return t; } - public static IEnumerable DetermineTypes(this IEnumerable exps, GeneratorContext context) - => exps.Select(x => x.DetermineType(context)).Where(x => x is not null /* if failed determine skip analyze */); + public static IEnumerable DetermineTypes(this IEnumerable exps, GeneratorContext context) + { + var list = exps.ToList(); + + var d = list.Select(x => x.DetermineType(context)) + .Where(x => x is not null /* if failed determine skip analyze */).ToList(); + + return d; + } - public static VeinClass DetermineType(this ExpressionSyntax exp, GeneratorContext context) + public static VeinComplexType DetermineType(this ExpressionSyntax exp, GeneratorContext context) { if (exp.CanOptimizationApply()) return exp.ForceOptimization().DetermineType(context); @@ -133,7 +140,7 @@ public static VeinClass DetermineType(this ExpressionSyntax exp, GeneratorContex throw new SkipStatementException(); } - public static VeinClass ResolveType(this AccessExpressionSyntax access, GeneratorContext context) + public static VeinComplexType ResolveType(this AccessExpressionSyntax access, GeneratorContext context) { var chain = access.ToChain().ToArray(); var lastToken = chain.Last(); @@ -157,10 +164,10 @@ public static VeinClass ResolveType(this AccessExpressionSyntax access, Generato public static VeinClass ResolveReturnType(this InvocationExpression inv, GeneratorContext context) => context.ResolveMethod(context.CurrentMethod.Owner, inv)?.ReturnType; - public static VeinClass ResolveReturnType(this InvocationExpression member, + public static VeinComplexType ResolveReturnType(this InvocationExpression member, GeneratorContext context, IEnumerable chain) { - var t = default(VeinClass); + var t = default(VeinComplexType); var prev_id = default(IdentifierExpression); var enumerator = chain.ToArray(); for (var i = 0; i != enumerator.Length; i++) From 903cace0d38587cff03f7e62d98cf4255ef0e767 Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Thu, 27 Jun 2024 00:41:00 +0300 Subject: [PATCH 6/7] add CheckCompatibility for checking generic types compatible and use complexType in FindMethod --- runtime/common/reflection/VeinClass.cs | 184 +++++++++++++++++++++++-- 1 file changed, 176 insertions(+), 8 deletions(-) diff --git a/runtime/common/reflection/VeinClass.cs b/runtime/common/reflection/VeinClass.cs index a0e34619..5162eddb 100644 --- a/runtime/common/reflection/VeinClass.cs +++ b/runtime/common/reflection/VeinClass.cs @@ -35,6 +35,10 @@ public class VeinClass : IEquatable, IAspectable public List Aspects { get; } = new(); #if DEBUG public ulong ReferenceID = DebugReference.Get(); + protected VeinClass() => CreationPlace = Environment.StackTrace; + +#else + protected VeinClass() {} #endif public string CreationPlace { get; set; } internal VeinClass(QualityTypeName name, VeinClass parent, VeinModule module) @@ -53,10 +57,7 @@ internal VeinClass(QualityTypeName name, VeinClass[] parents, VeinModule module) CreationPlace = Environment.StackTrace; } - protected VeinClass() - { - CreationPlace = Environment.StackTrace; - } + public bool IsSpecial => Flags.HasFlag(ClassFlags.Special); public bool IsPublic => Flags.HasFlag(ClassFlags.Public); @@ -82,7 +83,7 @@ public override string ToString() => $"{FullName}, {Flags}"; - public VeinMethod FindMethod(string name, IEnumerable user_types, bool includeThis = false) => + public VeinMethod FindMethod(string name, IEnumerable user_types, bool includeThis = false) => Methods.Concat(Parents.SelectMany(x => x.Methods)) .FirstOrDefault(x => { @@ -96,13 +97,180 @@ public VeinMethod FindMethod(string name, IEnumerable user_types, boo var args = x.Signature.Arguments.Where(z => includeThis || NotThis(z)).Select(z => z.ComplexType).ToList(); var argsHas = CheckCompatibility(userTypes, args); - if (!argsHas && !args.Any(z => z.IsGeneric)) - argsHas = CheckInheritance(userTypes.ToArray(), args.Select(z => z.Class).ToArray()); + if (!argsHas && !args.Any(z => z.IsGeneric) && !userTypes.Any(z => z.IsGeneric)) + argsHas = CheckInheritance(userTypes.Select(z => z.Class).ToArray(), args.Select(z => z.Class).ToArray()); return argsHas; }); - private bool CheckCompatibility(List userArgs, List methodArgs) + + private bool CheckCompatibility(List userArgs, List methodArgs) + { + if (userArgs.Count != methodArgs.Count) return false; + + Dictionary t2cMap = new(); + Dictionary t2tMap = new(); + + for (int i = 0; i < userArgs.Count; i++) + { + var userType = userArgs[i]; + var methodType = methodArgs[i]; + + if (methodType.IsGeneric) + { + if (!CheckGenericCompatibility(userType, methodType, t2cMap, t2tMap)) + return false; + } + else if (!CheckObjectCompatibility(methodType, userType)) + return false; + } + return true; + } + + private bool CheckGenericCompatibility(VeinComplexType userType, VeinComplexType methodType, Dictionary genericMap, Dictionary generic2genericMap) + { + var genericName = methodType.TypeArg.Name; + + if (userType.IsGeneric) + { + if (generic2genericMap.TryGetValue(genericName, out var val)) + return val.Name.Equals(genericName); + generic2genericMap[genericName] = userType.TypeArg; + return true; + } + + if (genericMap.TryGetValue(genericName, out var value)) + return value.FullName.Equals(userType.Class.FullName); + + genericMap[genericName] = userType.Class; + return true; + } + + private bool CheckObjectCompatibility(VeinComplexType methodClass, VeinComplexType userClass) + { + if (methodClass.IsGeneric) + return true; + if (methodClass.Class.TypeCode == TYPE_OBJECT && userClass.IsGeneric) + return true; + return false; + } + + private bool CheckCompatibilityV4(VeinComplexType[] userArgs, List methodArgs) + { + if (userArgs.Length != methodArgs.Count) return false; + + Dictionary genericMap = new(); + + for (int i = 0; i < userArgs.Length; i++) + { + var userType = userArgs[i]; + var methodType = methodArgs[i]; + + if (methodType.IsGeneric) + { + var genericName = methodType.TypeArg.Name; + + if (userType.IsGeneric) + { + if (!methodType.TypeArg.Name.Equals(userType.TypeArg.Name)) + return false; + } + else + { + if (genericMap.TryGetValue(genericName, out var value)) + { + if (!value.FullName.Equals(userType.Class.FullName) && userType.Class.TypeCode != TYPE_OBJECT) + return false; + } + else + genericMap[genericName] = userType.Class; + } + } + else + { + if (userType.IsGeneric) + return false; + if (!methodType.Class.FullName.Equals(userType.Class.FullName) && methodType.Class.TypeCode != TYPE_OBJECT && userType.Class.TypeCode != TYPE_OBJECT) + return false; + } + } + return true; + } + + private bool CheckCompatibilityV3(List userArgs, List methodArgs) + { + if (userArgs.Count != methodArgs.Count) return false; + + var genericMap = new Dictionary(); + + for (int i = 0; i < userArgs.Count; i++) + { + var userType = userArgs[i]; + var methodType = methodArgs[i]; + + if (methodType.IsGeneric) + { + var genericName = methodType.TypeArg.Name; + if (userType.IsGeneric) + { + if (!methodType.TypeArg.Name.Equals(userType.TypeArg.Name)) + return false; + } + else + { + if (genericMap.TryGetValue(genericName, out var value)) + { + if (!value.FullName.Equals(userType.Class.FullName)) + return false; + } + else + genericMap[genericName] = userType.Class; + } + } + else + { + if (userType.IsGeneric) + return false; + if (!methodType.Class.FullName.Equals(userType.Class.FullName)) + return false; + } + } + return true; + } + + + private bool CheckCompatibilityV2(List userArgs, List methodArgs) + { + if (userArgs.Count != methodArgs.Count) return false; + + Dictionary genericMap = new(); + + for (int i = 0; i < userArgs.Count; i++) + { + var userType = userArgs[i]; + var methodType = methodArgs[i]; + + if (methodType.IsGeneric) + { + var genericName = methodType.TypeArg.Name; + if (genericMap.TryGetValue(genericName, out var value)) + { + if (!value.FullName.Equals(userType.Class.FullName)) + return false; + } + else + genericMap[genericName] = userType.Class; + } + else + { + if (!methodType.Class.FullName.Equals(userType.Class.FullName)) + return false; + } + } + return true; + } + + private bool CheckCompatibilityV1(List userArgs, List methodArgs) { if (userArgs.Count != methodArgs.Count) return false; From 29f248bc702d07538ad4507135a21910fad0535e Mon Sep 17 00:00:00 2001 From: Yuuki Wesp Date: Thu, 27 Jun 2024 00:41:17 +0300 Subject: [PATCH 7/7] rewriter Testable.vein --- lib/vein.std/std/Out.vein | 15 ++++----------- lib/vein.std/std/Testable.vein | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/vein.std/std/Out.vein b/lib/vein.std/std/Out.vein index d0531b5c..d441bb1e 100644 --- a/lib/vein.std/std/Out.vein +++ b/lib/vein.std/std/Out.vein @@ -1,17 +1,10 @@ #space "std" - public static class Out { [native("__internal__", "@_println")] - public extern static @_println(value: Object): Void; - [native("__internal__", "@_println")] - public extern static @_println(value: i32): Void; - - public static print(value: string): Void - |> Out.@_println(value); - - public static print(value: i32): Void - |> Out.@_println(value); -} + public extern static _println(value: Object): Void; + public static print(value: Any): Void + |> Out._println(value); +} \ No newline at end of file diff --git a/lib/vein.std/std/Testable.vein b/lib/vein.std/std/Testable.vein index b46fbc7c..d60ceb14 100644 --- a/lib/vein.std/std/Testable.vein +++ b/lib/vein.std/std/Testable.vein @@ -1,16 +1,31 @@ #space "std" + public class Testable { public static master(): Void { Out.print("yamete..."); - aboba(1, "test string"); + + abobus(delMethod); + } + + + public static delMethod(i: i32): Void { + Out.print("yamete..."); } public static aboba(t: T, b: E): Void { Out.print("yamete..."); + Out.print(t); + Out.print(b); } -} \ No newline at end of file + + public static abobus(fn: testMethod): Void { + fn(255); + } +} + +global alias testMethod(i: i32): Void; \ No newline at end of file