Ejemplo n.º 1
0
 public static TypeBuilder WithEquatableEquals(this TypeBuilder builder, EntityModifier modifier = null)
 {
     return(builder.With(FunctionBuilder.Create(NameFactory.EqualOperator,
                                                ExpressionReadMode.ReadRequired, NameFactory.BoolNameReference(),
                                                Block.CreateStatement(
                                                    IfBranch.CreateIf(IsSame.Create(NameReference.CreateThised(), NameReference.Create("cmp")),
                                                                      new[] { Return.Create(BoolLiteral.CreateTrue()) }),
                                                    // let obj = cmp cast? Self
                                                    VariableDeclaration.CreateStatement("obj", null, ExpressionFactory.CheckedSelfCast("cmp",
                                                                                                                                       NameFactory.ReferenceNameReference(builder.CreateTypeNameReference(TypeMutability.ReadOnly)))),
                                                    // return this==obj.value
                                                    Return.Create(ExpressionFactory.IsEqual(NameReference.Create(NameFactory.ThisVariableName),
                                                                                            NameReference.Create("obj")))))
                         .SetModifier(EntityModifier.Override | modifier)
                         .Parameters(FunctionParameter.Create("cmp",
                                                              NameFactory.ReferenceNameReference(NameFactory.IEquatableNameReference(TypeMutability.ReadOnly))))));
 }
Ejemplo n.º 2
0
 public static TypeBuilder WithComparableCompare(this TypeBuilder builder, EntityModifier modifier = null)
 {
     return(builder.With(FunctionBuilder.Create(NameFactory.ComparableCompare,
                                                ExpressionReadMode.ReadRequired, NameFactory.OrderingNameReference(),
                                                Block.CreateStatement(
                                                    IfBranch.CreateIf(IsSame.Create(NameReference.CreateThised(), NameReference.Create("cmp")),
                                                                      new[] { Return.Create(NameFactory.OrderingEqualReference()) }),
                                                    // let obj = cmp cast? Self
                                                    VariableDeclaration.CreateStatement("obj", null, ExpressionFactory.CheckedSelfCast("cmp",
                                                                                                                                       NameFactory.ReferenceNameReference(builder.CreateTypeNameReference(TypeMutability.ReadOnly)))),
                                                    // return this.compare(obj.value)
                                                    Return.Create(FunctionCall.Create(NameReference.CreateThised(NameFactory.ComparableCompare),
                                                                                      NameReference.Create("obj")))))
                         .SetModifier(EntityModifier.Override | modifier)
                         .Parameters(FunctionParameter.Create("cmp",
                                                              NameFactory.ReferenceNameReference(NameFactory.IComparableNameReference(TypeMutability.ReadOnly))))));
 }
Ejemplo n.º 3
0
        public IErrorReporter ErrorAttachmentObjectOnStackAndHeap()
        {
            NameResolver resolver = null;

            foreach (var mutability in Options.AllMutabilityModes)
            {
                var env = Language.Environment.Create(new Options()
                {
                    DiscardingAnyExpressionDuringTests = true
                }
                                                      .SetMutability(mutability));
                var root_ns = env.Root;

                root_ns.AddBuilder(TypeBuilder.Create("Keeper")
                                   .With(VariableDeclaration.CreateStatement("world",
                                                                             NameFactory.PointerNameReference(NameFactory.IntNameReference()), Undef.Create(), EntityModifier.Public))
                                   .With(FunctionBuilder.CreateInitConstructor(Block.CreateStatement(
                                                                                   Assignment.CreateStatement(NameReference.CreateThised("world"), NameReference.Create("in_value"))
                                                                                   ))
                                         .Parameters(FunctionParameter.Create("in_value", NameFactory.PointerNameReference(NameFactory.IntNameReference())))));

                IExpression stack_init_value = ExpressionFactory.StackConstructor("Keeper", NameReference.Create("i"));
                IExpression heap_init_value  = ExpressionFactory.HeapConstructor("Keeper", NameReference.Create("i"));

                FunctionDefinition func = root_ns.AddBuilder(FunctionBuilder.Create("notimportant",
                                                                                    ExpressionReadMode.OptionalUse,
                                                                                    NameFactory.UnitNameReference(),

                                                                                    Block.CreateStatement(
                                                                                        VariableDeclaration.CreateStatement("i", NameFactory.ReferenceNameReference(NameFactory.IntNameReference()),
                                                                                                                            IntLiteral.Create("0"), EntityModifier.Reassignable),
                                                                                        // this is incorrect, because we are creating attachment object as value, dropping the lifetime
                                                                                        VariableDeclaration.CreateStatement("attach1", NameReference.Create("Keeper"), stack_init_value),
                                                                                        ExpressionFactory.Readout("attach1"),
                                                                                        // this is incorrect, because we are creating attachment object as global instance, dropping the lifetime
                                                                                        VariableDeclaration.CreateStatement("attach2", NameFactory.PointerNameReference(NameReference.Create("Keeper")),
                                                                                                                            heap_init_value),
                                                                                        ExpressionFactory.Readout("attach2")
                                                                                        )));


                resolver = NameResolver.Create(env);

                Assert.IsTrue(resolver.ErrorManager.HasError(ErrorCode.EscapingReference, stack_init_value));
                Assert.IsTrue(resolver.ErrorManager.HasError(ErrorCode.EscapingReference, heap_init_value));
                Assert.AreEqual(2, resolver.ErrorManager.Errors.Count);
            }
            return(resolver);
        }
Ejemplo n.º 4
0
        public IErrorReporter ErrorEscapingReferenceWithAttachmentObject()
        {
            NameResolver resolver = null;

            foreach (var mutability in Options.AllMutabilityModes)
            {
                var env = Language.Environment.Create(new Options()
                {
                    DiscardingAnyExpressionDuringTests = true
                }
                                                      .SetMutability(mutability));
                var root_ns = env.Root;

                root_ns.AddBuilder(TypeBuilder.Create("Keeper")
                                   .With(VariableDeclaration.CreateStatement("world",
                                                                             NameFactory.PointerNameReference(NameFactory.IntNameReference()), Undef.Create(), EntityModifier.Public))
                                   .With(FunctionBuilder.CreateInitConstructor(Block.CreateStatement(
                                                                                   Assignment.CreateStatement(NameReference.CreateThised("world"), NameReference.Create("in_value"))
                                                                                   ))
                                         .Parameters(FunctionParameter.Create("in_value", NameFactory.PointerNameReference(NameFactory.IntNameReference())))));

                Assignment assign = Assignment.CreateStatement(NameReference.Create("attach"),
                                                               ExpressionFactory.StackConstructor("Keeper", NameReference.Create("i"))).Cast <Assignment>();

                FunctionDefinition func = root_ns.AddBuilder(FunctionBuilder.Create("notimportant",
                                                                                    ExpressionReadMode.OptionalUse,
                                                                                    NameFactory.UnitNameReference(),

                                                                                    Block.CreateStatement(
                                                                                        VariableDeclaration.CreateStatement("attach", NameReference.Create("Keeper"),
                                                                                                                            Undef.Create(), EntityModifier.Reassignable),
                                                                                        Block.CreateStatement(
                                                                                            VariableDeclaration.CreateStatement("i", NameFactory.ReferenceNameReference(NameFactory.IntNameReference()),
                                                                                                                                IntLiteral.Create("0")),
                                                                                            // cannot execute this assignment because the reference would move from here to outer scope
                                                                                            // just wrapped in `Keeper` instance
                                                                                            // please note this `Keeper` instance is attached to `i`
                                                                                            // (triggered by conversion reference->pointer in constructor), so it cannot outlive it
                                                                                            assign,
                                                                                            ExpressionFactory.Readout("attach")
                                                                                            )
                                                                                        )));


                resolver = NameResolver.Create(env);

                Assert.AreEqual(1, resolver.ErrorManager.Errors.Count);
                Assert.IsTrue(resolver.ErrorManager.HasError(ErrorCode.EscapingReference, assign.RhsValue));
            }
            return(resolver);
        }
Ejemplo n.º 5
0
 public static FunctionDefinition BasicConstructor(string[] names, INameReference[] typenames)
 {
     return(FunctionDefinition.CreateInitConstructor(EntityModifier.None,
                                                     Enumerable.Range(0, names.Length).Select(i => FunctionParameter.Create(names[i], typenames[i])),
                                                     Block.CreateStatement(
                                                         names.Select(s => Assignment.CreateStatement(NameReference.CreateThised(s), NameReference.Create(s))))));
 }
Ejemplo n.º 6
0
        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;
        }