private void compute(ComputationContext ctx) { foreach (TypeDefinition trait in this.AssociatedTraits) { trait.computeAncestors(ctx, new HashSet <TypeDefinition>()); } computeAncestors(ctx, new HashSet <TypeDefinition>()); IEnumerable <INode> owned_nodes = this.ChildrenNodes.Concat(this.AssociatedTraits.SelectMany(it => it.ChildrenNodes)); owned_nodes.WhereType <ISurfable>().ForEach(it => it.Surfed(ctx)); // -- if (this.Modifier.HasMutable && (!this.Modifier.HasHeapOnly || this.NestedFunctions.Any(it => it.IsCopyInitConstructor(ctx)))) { // creating counterparts of mutable methods // todo: this should be implemented differently -- instead of creating methods, creating expressions // copy-cons, mutable call, return obj // on demand, in-place, when const non-existing method is called HashSet <string> const_functions = this.NestedFunctions.Where(f => !f.Modifier.HasMutable).Concat( this.Inheritance.OrderedAncestorsIncludingObject.SelectMany(it => it.TargetType.NestedFunctions .Where(f => !f.Modifier.HasMutable && !f.Modifier.HasPrivate))) .Select(it => it.Name.Name) .ToHashSet(); foreach (FunctionDefinition func in this.NestedFunctions.Where(it => it.Modifier.HasMutable).StoreReadOnly()) { string const_name = NameFactory.UnmutableName(func.Name.Name); if (const_functions.Contains(const_name)) { continue; } if (!ctx.Env.IsOfUnitType(func.ResultTypeName)) { continue; } INameReference result_typename = NameFactory.ItNameReference(); if (this.Modifier.HasHeapOnly) { result_typename = NameFactory.PointerNameReference(result_typename); } var instructions = new List <IExpression>(); if (this.Modifier.HasHeapOnly) { instructions.Add(VariableDeclaration.CreateStatement("cp", null, ExpressionFactory.HeapConstructor(NameFactory.ItNameReference(), NameReference.CreateThised()))); } else { // explicit typename is needed, because otherwise we would get a reference to this, not value (copy) instructions.Add(VariableDeclaration.CreateStatement("cp", NameFactory.ItNameReference(), NameReference.CreateThised())); } instructions.Add(FunctionCall.Create(NameReference.Create("cp", func.Name.Name), func.Parameters.Select(it => NameReference.Create(it.Name.Name)).ToArray())); instructions.Add(Return.Create(NameReference.Create("cp"))); FunctionDefinition const_func = FunctionBuilder.Create(const_name, func.Name.Parameters, result_typename, Block.CreateStatement(instructions)) .SetModifier(EntityModifier.AutoGenerated) // native methods have parameters with forbidden read .Parameters(func.Parameters.Select(it => it.CloneAsReadable())); this.AddNode(const_func); const_func.Surfed(ctx); } } if (this.Modifier.HasEnum) { // finally we are at point when we know from which offset we can start setting ids for enum cases FunctionDefinition zero_constructor = this.NestedFunctions.Single(it => it.IsZeroConstructor() && it.Modifier.HasStatic); if (zero_constructor.IsComputed) { throw new System.Exception("Internal error -- we cannot alter the body after the function was already computed"); } int enum_ord = this.InstanceOf.PrimaryAncestors(ctx).Select(it => it.TargetType) .Sum(it => it.NestedFields.Count(f => f.Modifier.HasEnum)); foreach (VariableDeclaration decl in this.NestedFields.Where(it => it.Modifier.HasEnum)) { zero_constructor.UserBody.Append(decl.CreateFieldInitCall(NatLiteral.Create($"{enum_ord++}"))); } } // base method -> derived (here) method var virtual_mapping = new VirtualTable(isPartial: false); foreach (EntityInstance parent_instance in this.Inheritance.MinimalParentsIncludingObject .Concat(this.AssociatedTraits.SelectMany(it => it.Inheritance.MinimalParentsIncludingObject)) .Distinct(EntityInstance.Comparer) .Reverse()) { virtual_mapping.OverrideWith(parent_instance.TargetType.InheritanceVirtualTable); } IEnumerable <FunctionDefinition> all_nested_functions = this.AllNestedFunctions .Concat(this.AssociatedTraits.SelectMany(it => it.AllNestedFunctions)); // derived (here) method -> base methods Dictionary <FunctionDefinition, List <FunctionDefinition> > derivation_mapping = all_nested_functions .Where(it => it.Modifier.HasOverride) .ToDictionary(it => it, it => new List <FunctionDefinition>()); var inherited_member_instances = new HashSet <EntityInstance>(EntityInstance.Comparer); var missing_func_implementations = new List <FunctionDefinition>(); foreach (EntityInstance ancestor in this.Inheritance.OrderedAncestorsIncludingObject .Concat(this.AssociatedTraits.SelectMany(it => it.Inheritance.OrderedAncestorsIncludingObject)) .Distinct(EntityInstance.Comparer)) { // special case are properties -- properties are in fact not inherited, their accessors are // however user sees properties, so we get members here (including properties), but when we compute // what function overrode which, we use really functions, and only having them in hand we check if // they are property accessors IEnumerable <EntityInstance> members = (ancestor.TargetType.AvailableEntities ?? Enumerable.Empty <EntityInstance>()) .Where(it => it.Target is IMember); foreach (EntityInstance entity_instance in members .Where(it => it.Target.Modifier.HasPublic || it.Target.Modifier.HasProtected) .Where(it => !(it.Target is FunctionDefinition func) || !func.IsAnyConstructor())) { EntityInstance translated = entity_instance.TranslateThrough(ancestor); inherited_member_instances.Add(translated); } foreach (FunctionDerivation deriv_info in TypeDefinitionExtension.PairDerivations(ctx, ancestor, all_nested_functions)) { if (deriv_info.Derived == null) { // we can skip implementation or abstract signature of the function in the abstract type if (deriv_info.Base.Modifier.RequiresOverride && !this.Modifier.IsAbstract) { missing_func_implementations.Add(deriv_info.Base); } } else { { if (deriv_info.Base.IsPropertyAccessor(out Property base_property)) { EntityInstance base_prop_instance = base_property.InstanceOf.TranslateThrough(ancestor); inherited_member_instances.Remove(base_prop_instance); } EntityInstance base_instance = deriv_info.Base.InstanceOf.TranslateThrough(ancestor); inherited_member_instances.Remove(base_instance); } if (deriv_info.Derived.Modifier.HasOverride) { derivation_mapping[deriv_info.Derived].Add(deriv_info.Base); // user does not have to repeat "pinned" all the time, but for easier tracking of pinned methods // we add it automatically if (deriv_info.Base.Modifier.HasPinned) { deriv_info.Derived.SetModifier(deriv_info.Derived.Modifier | EntityModifier.Pinned); } if (deriv_info.Base.Modifier.HasHeapOnly != deriv_info.Derived.Modifier.HasHeapOnly) { ctx.AddError(ErrorCode.HeapRequirementChangedOnOverride, deriv_info.Derived); } } else if (!deriv_info.Base.Modifier.IsSealed) { ctx.AddError(ErrorCode.MissingOverrideModifier, deriv_info.Derived); } if (!deriv_info.Base.Modifier.IsSealed) { virtual_mapping.Update(deriv_info.Base, deriv_info.Derived); // the rationale for keeping the same access level is this // narrowing is pretty easy to skip by downcasting // expanding looks like a good idea, but... -- the author of original type // maybe had better understanding why given function is private/protected and not protected/public // it is better to keep it safe, despite little annoyance (additional wrapper), than finding out // how painful is violating that "good reason" because it was too easy to type "public" if (!deriv_info.Base.Modifier.SameAccess(deriv_info.Derived.Modifier)) { ctx.AddError(ErrorCode.AlteredAccessLevel, deriv_info.Derived.Modifier); } } else if (deriv_info.Derived.Modifier.HasOverride) { ctx.AddError(ErrorCode.CannotOverrideSealedMethod, deriv_info.Derived); } } } } foreach (FunctionDefinition missing_impl in missing_func_implementations) { if (!isDerivedByAncestors(missing_impl)) { ctx.AddError(ErrorCode.BaseFunctionMissingImplementation, this, missing_impl); } } // here we eliminate "duplicate" entries -- if we have some method in ancestor A // and this method is overridden in ancestor B, then we would like to have // only method B listed, not both foreach (EntityInstance inherited in inherited_member_instances.ToArray()) { IEntity target = inherited.Target; if (target is Property prop) { target = prop.Getter; } if (target is FunctionDefinition func && isDerivedByAncestors(func)) { inherited_member_instances.Remove(inherited); } } this.InheritanceVirtualTable = virtual_mapping; this.DerivationTable = new DerivationTable(ctx, this, derivation_mapping); this.availableEntities = ScopeTable.Combine(this.AvailableEntities, inherited_member_instances); foreach (FunctionDefinition func in derivation_mapping.Where(it => !it.Value.Any()).Select(it => it.Key)) { ctx.AddError(ErrorCode.NothingToOverride, func); } this.isEvaluated = true; }