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(); } }
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(); } }
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); }
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); } } }
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); } } }