예제 #1
0
        internal static bool MutabilityMatches(IOptions options, TypeMutability inputMutability, TypeMutability targetMutability)
        {
            if (inputMutability.HasFlag(TypeMutability.Reassignable))
            {
                inputMutability ^= TypeMutability.Reassignable;
            }
            if (targetMutability.HasFlag(TypeMutability.Reassignable))
            {
                targetMutability ^= TypeMutability.Reassignable;
            }

            if (options.MutabilityMode == MutabilityModeOption.OnlyAssignability)
            {
                return(true);
            }

            switch (inputMutability)
            {
            case TypeMutability.DualConstMutable: return(true);

            case TypeMutability.ForceConst:
            case TypeMutability.ConstAsSource:
                return(targetMutability != TypeMutability.ForceMutable && targetMutability != TypeMutability.GenericUnknownMutability);

            case TypeMutability.ForceMutable:
            case TypeMutability.GenericUnknownMutability:
                return(targetMutability != TypeMutability.ConstAsSource && targetMutability != TypeMutability.ForceConst);

            case TypeMutability.ReadOnly: return(targetMutability == TypeMutability.ReadOnly);

            default: throw new NotImplementedException();
            }
        }
예제 #2
0
        public static string StringPrefix(this TypeMutability flag)
        {
            string s = "";

            if (flag.HasFlag(TypeMutability.Reassignable))
            {
                s     = "=";
                flag ^= TypeMutability.Reassignable;
            }
            switch (flag)
            {
            case TypeMutability.DualConstMutable: return($"{s}dual ");

            case TypeMutability.ForceConst: return($"{s}fconst ");

            case TypeMutability.ForceMutable: return($"{s}mut ");

            case TypeMutability.ReadOnly: return($"{s}neut ");

            case TypeMutability.None: return($"{s}");

            case TypeMutability.GenericUnknownMutability: return("{s}g ");

            case TypeMutability.ConstAsSource: return($"{s} ");

            default: throw new Exception();
            }
        }
예제 #3
0
        public ConstraintMatch ArgumentMatchesParameterConstraints(ComputationContext ctx, EntityInstance closedTemplate,
                                                                   TemplateParameter param)
        {
            if (this.TargetsTemplateParameter && this.TemplateParameterTarget == param)
            {
                return(ConstraintMatch.Yes);
            }

            TypeMutability arg_mutability = this.SurfaceMutabilityOfType(ctx);

            if (param.Constraint.Modifier.HasConst &&
                arg_mutability != TypeMutability.ForceConst && arg_mutability != TypeMutability.ConstAsSource)
            {
                return(ConstraintMatch.MutabilityViolation);
            }
            else if (param.Constraint.Modifier.HasMutable && arg_mutability != TypeMutability.ForceMutable)
            {
                return(ConstraintMatch.MutabilityViolation);
            }
            else if (param.Constraint.Modifier.HasReassignable && !arg_mutability.HasFlag(TypeMutability.Reassignable))
            {
                return(ConstraintMatch.AssignabilityViolation);
            }

            // 'inherits' part of constraint
            foreach (EntityInstance constraint_inherits in param.Constraint.TranslateInherits(closedTemplate))
            {
                TypeMatch match = TypeMatcher.Matches(ctx, this, constraint_inherits,
                                                      TypeMatching.Create(ctx.Env.Options.InterfaceDuckTyping, allowSlicing: true));
                if (match.IsMismatch())
                {
                    return(ConstraintMatch.InheritsViolation);
                }
            }

            {
                VirtualTable vtable = EntityInstanceExtension.BuildDuckVirtualTable(ctx, this, param.AssociatedType.InstanceOf,
                                                                                    allowPartial: false);
                if (vtable == null)
                {
                    return(ConstraintMatch.MissingFunction);
                }
            }


            // 'base-of' part of constraint
            IEnumerable <IEntityInstance> arg_bases = (this.TargetsTemplateParameter
                ? this.TargetType.TemplateParameter.Constraint.TranslateBaseOf(closedTemplate)
                : Enumerable.Empty <EntityInstance>()
                                                       )
                                                      .Concat(this);

            foreach (EntityInstance constraint_base in param.Constraint.TranslateBaseOf(closedTemplate))
            {
                if (!arg_bases.Any(it => !constraint_base.MatchesTarget(ctx, it, TypeMatching.Create(ctx.Env.Options.InterfaceDuckTyping, allowSlicing: true))
                                   .IsMismatch()))
                {
                    return(ConstraintMatch.BaseViolation);
                }
            }

            return(ConstraintMatch.Yes);
        }
예제 #4
0
        public void Validate(ComputationContext ctx)
        {
            if (this.Resolution == null)
            {
                return;
            }

            FunctionDefinition enclosing_func = this.EnclosingScope <FunctionDefinition>();

            if (this.Resolution.TargetFunction.Modifier.IsPolymorphic &&
                enclosing_func != null && enclosing_func.IsAnyConstructor() &&
                !enclosing_func.ContainingType().Modifier.IsSealed)
            {
                ctx.AddError(ErrorCode.VirtualCallFromConstructor, this);
            }

            if (this.mode != CallMode.Constructor && this.Resolution.TargetFunction.IsAnyConstructor())
            {
                ctx.AddError(ErrorCode.ConstructorCallFromFunctionBody, this);
            }

            {
                bool is_recall = isRecall(out FunctionDefinition curr_func, out FunctionDefinition binding_func);
                if (!ctx.Env.Options.AllowNamedSelf && binding_func != null)
                {
                    if (this.Name.Name != NameFactory.RecurFunctionName && is_recall)
                    {
                        ctx.ErrorManager.AddError(ErrorCode.NamedRecursiveFunctionReference, this.Name);
                    }
                    else if (!this.Name.IsSuperReference && curr_func != null)
                    {
                        FunctionDefinition super_func = curr_func.TryGetSuperFunction(ctx);
                        if (super_func == binding_func)
                        {
                            ctx.ErrorManager.AddError(ErrorCode.NamedRecursiveFunctionReference, this.Name);
                        }
                    }
                }
            }

            {
                if (this.Name.TargetsCurrentInstanceMember(out IMember member))
                {
                    FunctionDefinition callee = member.CastFunction();
                    FunctionDefinition func   = this.EnclosingScope <FunctionDefinition>();
                    if (!func.Modifier.HasMutable && !func.IsAnyConstructor() && callee.Modifier.HasMutable)
                    {
                        ctx.AddError(ErrorCode.CallingMutableFromImmutableMethod, this);
                    }
                }
            }

            if (this.Resolution.MetaThisArgument != null)
            {
                // we cannot call mutable methods on neutral instance as well, because in such case we could
                // pass const instance (of mutable type) as neutral instance (aliasing const instance)
                // and then call mutable method making "const" guarantee invalid

                TypeMutability this_mutability = this.Resolution.MetaThisArgument.Expression.Evaluation.Components.MutabilityOfType(ctx);
                if (!this_mutability.HasFlag(TypeMutability.ForceMutable) && this.Resolution.TargetFunction.Modifier.HasMutable)
                {
                    ctx.AddError(ErrorCode.AlteringNonMutableInstance, this);
                }
            }


            if (this.Resolution.TargetFunction.Modifier.HasHeapOnly)
            {
                FunctionDefinition func = this.EnclosingScope <FunctionDefinition>();
                if ((this.Name.Prefix != null && !ctx.Env.IsPointerOfType(this.Name.Prefix.Evaluation.Components)) ||
                    (this.Name.Prefix == null && !func.Modifier.HasHeapOnly))
                {
                    ctx.AddError(ErrorCode.CallingHeapFunctionWithValue, this);
                }
            }
        }
예제 #5
0
        public override void Validate(ComputationContext ctx)
        {
            base.Validate(ctx);

            if (this.Modifier.HasTrait)
            {
                if (!this.Name.Parameters.Any())
                {
                    ctx.AddError(ErrorCode.NonGenericTrait, this);
                }
                else
                {
                    if (!this.Constraints.Any())
                    {
                        ctx.AddError(ErrorCode.UnconstrainedTrait, this);
                    }

                    TypeDefinition host_type = AssociatedHost;
                    if (host_type == null)
                    {
                        ctx.AddError(ErrorCode.MissingHostTypeForTrait, this);
                    }
                }
            }

            if (this.Modifier.HasAssociatedReference)
            {
                if (!this.Modifier.IsSealed)
                {
                    ctx.AddError(ErrorCode.AssociatedReferenceRequiresSealedType, this.Modifier);
                }

                {
                    IEnumerable <FunctionDefinition> constructors = this.NestedFunctions.Where(it => it.IsInitConstructor());

                    foreach (FunctionDefinition cons in constructors.Skip(1))
                    {
                        ctx.AddError(ErrorCode.AssociatedReferenceRequiresSingleConstructor, cons);
                    }

                    FunctionDefinition primary_cons = constructors.First();
                    if (primary_cons.Parameters.Count != 1)
                    {
                        ctx.AddError(ErrorCode.AssociatedReferenceRequiresSingleParameter, primary_cons);
                    }
                    else
                    {
                        FunctionParameter cons_param = primary_cons.Parameters.Single();
                        if (!ctx.Env.IsReferenceOfType(cons_param.TypeName.Evaluation.Components))
                        {
                            ctx.AddError(ErrorCode.AssociatedReferenceRequiresReferenceParameter, cons_param.TypeName);
                        }
                        else if (cons_param.IsVariadic)
                        {
                            ctx.AddError(ErrorCode.AssociatedReferenceRequiresNonVariadicParameter, cons_param);
                        }
                        else if (cons_param.IsOptional)
                        {
                            ctx.AddError(ErrorCode.AssociatedReferenceRequiresNonOptionalParameter, cons_param);
                        }
                    }
                }

                {
                    IEnumerable <VariableDeclaration> ref_fields = this.NestedFields
                                                                   .Where(it => ctx.Env.IsReferenceOfType(it.Evaluation.Components));

                    foreach (VariableDeclaration decl in ref_fields.Skip(1))
                    {
                        ctx.AddError(ErrorCode.AssociatedReferenceRequiresSingleReferenceField, decl);
                    }
                }
            }

            {
                IEnumerable <VariableDeclaration> ref_fields = this.NestedFields
                                                               .Where(it => ctx.Env.IsReferenceOfType(it.Evaluation.Components));

                VariableDeclaration primary = ref_fields.FirstOrDefault();
                if (primary != null && primary.IsReassignable(ctx))
                {
                    ctx.AddError(ErrorCode.ReferenceFieldCannotBeReassignable, primary);
                }
            }

            foreach (NameReference parent in this.ParentNames.Skip(1))
            {
                if (parent.Evaluation.Components.Cast <EntityInstance>().TargetType.IsTypeImplementation)
                {
                    ctx.AddError(ErrorCode.TypeImplementationAsSecondaryParent, parent);
                }
            }

            {
                TypeDefinition primary_parent = this.Inheritance.GetTypeImplementationParent()?.TargetType;
                if (primary_parent != null)
                {
                    if (this.Modifier.HasEnum != primary_parent.Modifier.HasEnum)
                    {
                        ctx.AddError(ErrorCode.EnumCrossInheritance, this);
                    }

                    if (this.Modifier.HasTrait)
                    {
                        ctx.AddError(ErrorCode.TraitInheritingTypeImplementation, this.ParentNames.First());
                    }
                }
            }

            if (!this.Modifier.IsAbstract)
            {
                foreach (FunctionDefinition func in this.AllNestedFunctions)
                {
                    if (func.Modifier.HasAbstract)
                    {
                        ctx.AddError(ErrorCode.NonAbstractTypeWithAbstractMethod, func);
                    }
                    else if (func.Modifier.HasBase && this.Modifier.IsSealed)
                    {
                        ctx.AddError(ErrorCode.SealedTypeWithBaseMethod, func);
                    }
                }
            }

            {
                TypeMutability current_mutability = this.InstanceOf.MutabilityOfType(ctx);
                if (current_mutability != TypeMutability.ForceMutable)
                {
                    // the above check is more than checking just a flag
                    // for template types the mutability depends on parameter constraints
                    foreach (NameReference parent in this.ParentNames)
                    {
                        TypeMutability parent_mutability = parent.Evaluation.Components.MutabilityOfType(ctx);
                        if (parent_mutability == TypeMutability.ForceMutable)
                        {
                            ctx.AddError(ErrorCode.InheritanceMutabilityViolation, parent);
                        }
                    }
                }
            }

            if (!this.Modifier.HasMutable)
            {
                foreach (VariableDeclaration field in this.AllNestedFields)
                {
                    if (field.Modifier.HasReassignable)
                    {
                        ctx.AddError(ErrorCode.MutableFieldInImmutableType, field);
                    }
                    else
                    {
                        TypeMutability field_eval_mutability = field.Evaluation.Components.MutabilityOfType(ctx);
                        if (!field_eval_mutability.HasFlag(TypeMutability.ConstAsSource) &&
                            !field_eval_mutability.HasFlag(TypeMutability.GenericUnknownMutability) &&
                            !field_eval_mutability.HasFlag(TypeMutability.ForceConst))
                        {
                            ctx.AddError(ErrorCode.MutableFieldInImmutableType, field);
                        }
                    }
                }
                foreach (FunctionDefinition func in this.NestedFunctions
                         .Where(it => it.Modifier.HasMutable))
                {
                    ctx.AddError(ErrorCode.MutableFunctionInImmutableType, func);
                }

                foreach (Property property in this.NestedProperties
                         .Where(it => it.Setter != null))
                {
                    ctx.AddError(ErrorCode.PropertySetterInImmutableType, property);
                }
            }
        }