private static bool interchangeableTypesTo(ComputationContext ctx, IEntityInstance input, IEntityInstance target) { bool is_input_sealed = input.EnumerateAll() .Select(it => { ctx.Env.Dereference(it, out IEntityInstance result); return(result); }) .SelectMany(it => it.EnumerateAll()) .All(it => it.Target.Modifier.IsSealed); if (is_input_sealed) { TypeMatch match = input.MatchesTarget(ctx, target, TypeMatching.Create(ctx.Env.Options.InterfaceDuckTyping, allowSlicing: true).WithIgnoredMutability(true)); // example: we cannot check if x (of Int) is IAlien because Int is sealed and there is no way // it could be something else not available in its inheritance tree if (!match.Passed) { return(false); } } return(true); }
public void Validate(ComputationContext ctx) { foreach (NameReference base_of in this.BaseOfNames) { // we allow slicing because we just need if the hierarchy is not reversed, not to pass actual values if (this.InheritsNames.Any(it => { TypeMatch match = it.Evaluation.Components.MatchesTarget(ctx, base_of.Evaluation.Components, TypeMatching.Create(ctx.Env.Options.InterfaceDuckTyping, allowSlicing: true)); return(match == TypeMatch.Same || match == TypeMatch.Substitute); })) { ctx.AddError(ErrorCode.ConstraintConflictingTypeHierarchy, base_of); } } // the left side: target match (i.e. template inner parameter type) -> template // the right side: this -> template parameter -> name definition -> template if (this.Name.Binding.Match.Instance.Target.Owner != this.Owner.Owner.Owner) { ctx.AddError(ErrorCode.MisplacedConstraint, this); } }
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); }