示例#1
0
        private static EntityInstance selectFromLowestCommonAncestorPool(ComputationContext ctx, EntityInstance type,
                                                                         HashSet <EntityInstance> pool)
        {
            if (type == null)
            {
                return(null);
            }

            if (pool.Contains(type))
            {
                return(type);
            }

            EntityInstance implementation_parent = type.Inheritance(ctx).GetTypeImplementationParent();
            // prefer LCA as implementation
            EntityInstance via_implementation = selectFromLowestCommonAncestorPool(ctx, implementation_parent, pool);

            if (via_implementation != null)
            {
                return(via_implementation);
            }

            foreach (EntityInstance interface_parent in type.Inheritance(ctx).MinimalParentsIncludingObject
                     .Where(it => it != implementation_parent))
            {
                EntityInstance via_interface = selectFromLowestCommonAncestorPool(ctx, interface_parent, pool);
                if (via_interface != null)
                {
                    return(via_interface);
                }
            }

            return(null);
        }
示例#2
0
        public static TypeMatch Matches(ComputationContext ctx, EntityInstance input, EntityInstance target, TypeMatching matching)
        {
            if (input.IsJoker || target.IsJoker)
            {
                return(TypeMatch.Same);
            }

            if (!target.Target.IsType() || !input.Target.IsType())
            {
                return(TypeMatch.No);
            }

            if (input.Lifetime.IsAttached)
            {
                matching = matching.WithLifetimeCheck(true, input.Lifetime, target.Lifetime);
            }


            {
                IEnumerable <FunctionDefinition> in_conv = target.TargetType.ImplicitInConverters().StoreReadOnly();
                bool conv_slicing_sub = input.TargetType.AllowSlicedSubstitution;
                foreach (FunctionDefinition func in in_conv)
                {
                    IEntityInstance conv_type = func.Parameters.Single().TypeName.Evaluated(ctx, EvaluationCall.AdHocCrossJump).TranslateThrough(target);
                    if (target.IsIdentical(conv_type)) // preventing circular conversion check
                    {
                        continue;
                    }

                    TypeMatch m = input.MatchesTarget(ctx, conv_type, matching.WithSlicing(conv_slicing_sub));
                    if (m == TypeMatch.Same || m == TypeMatch.Substitute)
                    {
                        return(TypeMatch.InConversion);
                    }
                }
            }


            if (ctx.Env.IsReferenceOfType(target))
            {
                if (ctx.Env.IsPointerLikeOfType(input))
                {
                    // note, that we could have reference to pointer in case of the target, we have to unpack both
                    // to the level of the value types
                    int target_dereferences = ctx.Env.Dereference(target, out IEntityInstance inner_target_type);
                    int input_dereferences  = ctx.Env.Dereference(input, out IEntityInstance inner_input_type);

                    TypeMatch m = inner_input_type.MatchesTarget(ctx, inner_target_type, matching
                                                                 .WithSlicing(true)
                                                                 .WithMutabilityCheckRequest(true)
                                                                 .WithLifetimeCheck(true, ctx.Env.IsReferenceOfType(input) ? input.Lifetime : Lifetime.Timeless, target.Lifetime));
                    if (target_dereferences > input_dereferences && !m.IsMismatch())
                    {
                        m |= TypeMatch.ImplicitReference;
                    }
                    return(m);
                }
                else
                {
                    ctx.Env.Dereferenced(target, out IEntityInstance inner_target_type);

                    TypeMatch m = input.MatchesTarget(ctx, inner_target_type, matching
                                                      .WithSlicing(true)
                                                      .WithMutabilityCheckRequest(true)
                                                      .WithLifetimeCheck(true, input.Lifetime, target.Lifetime));
                    if (m == TypeMatch.Same || m == TypeMatch.Substitute)
                    {
                        return(m | TypeMatch.ImplicitReference);
                    }
                    else
                    {
                        return(m);
                    }
                }
            }
            // automatic dereferencing pointers
            else if (ctx.Env.IsPointerLikeOfType(input))
            {
                int input_dereferences;
                {
                    input_dereferences = ctx.Env.Dereference(input, out IEntityInstance dummy);
                }

                // we check if we have more refs/ptrs in input than in target
                if (input_dereferences > (ctx.Env.IsPointerOfType(target) ? 1 : 0))
                {
                    ctx.Env.DereferencedOnce(input, out IEntityInstance inner_input_type, out bool dummy);

                    TypeMatch m = inner_input_type.MatchesTarget(ctx, target, matching.WithSlicing(true));
                    if (m.Passed)
                    {
                        return(m | TypeMatch.AutoDereference);
                    }
                }
                else
                {
                    matching = matching.WithMutabilityCheckRequest(true)
                    ;
                }
            }

            if (ctx.Env.IsReferenceOfType(input) && ctx.Env.IsPointerOfType(target))
            {
                // note, that we could have reference to pointer in case of the target, we have to unpack both
                // to the level of the value types
                ctx.Env.DereferencedOnce(target, out IEntityInstance inner_target_type, out bool dummy1);
                ctx.Env.DereferencedOnce(input, out IEntityInstance inner_input_type, out bool dummy2);

                TypeMatch m = inner_input_type.MatchesTarget(ctx, inner_target_type, matching
                                                             .WithSlicing(true)
                                                             .WithMutabilityCheckRequest(true)
                                                             .WithLifetimeCheck(true, input.Lifetime, Lifetime.Timeless));
                if (!m.IsMismatch())
                {
                    m |= TypeMatch.Attachment;
                }
                return(m);
            }


            {
                IEnumerable <FunctionDefinition> out_conv = input.TargetType.ImplicitOutConverters().StoreReadOnly();
                bool conv_slicing_sub = input.TargetType.AllowSlicedSubstitution;
                foreach (FunctionDefinition func in out_conv)
                {
                    IEntityInstance conv_type = func.ResultTypeName.Evaluated(ctx, EvaluationCall.AdHocCrossJump).TranslateThrough(input);
                    //if (target == conv_type) // preventing circular conversion check
                    //  continue;

                    TypeMatch m = conv_type.MatchesTarget(ctx, target, matching.WithSlicing(conv_slicing_sub));
                    if (m == TypeMatch.Same || m == TypeMatch.Substitute)
                    {
                        return(TypeMatch.OutConversion);
                    }
                }
            }

            if (target.TargetType.AllowSlicedSubstitution)
            {
                matching.AllowSlicing = true;
            }


            TypeMatch match = TypeMatch.No;

            TypeMutability input_mutability = input.MutabilityOfType(ctx);

            if (matching.AllowSlicing)
            {
                IEnumerable <TypeAncestor> input_family = new[] { new TypeAncestor(input, 0) }
                .Concat(input.Inheritance(ctx).OrderedTypeAncestorsIncludingObject
                        // enum substitution works in reverse so we have to exclude these from here
                        .Where(it => !it.AncestorInstance.TargetType.Modifier.HasEnum));

                foreach (TypeAncestor inherited_input in input_family)
                {
                    if (matchTypes(ctx, input_mutability, input.Lifetime, inherited_input.AncestorInstance,
                                   target, matching, inherited_input.Distance, out TypeMatch m))
                    {
                        return(m);
                    }
                    else if (m != TypeMatch.No) // getting more specific rejection than just bare one
                    {
                        match = m;
                    }
                }
            }
            // when slicing is disabled we can compare try to substitute only the same type
            else if (input.Target == target.Target)
            {
                if (matchTypes(ctx, input_mutability, input.Lifetime, input, target, matching, distance: 0, match: out match))
                {
                    if (match != TypeMatch.Same && !match.IsMismatch())
                    {
                        throw new Exception($"Internal exception {match}");
                    }
                    return(match);
                }
            }

            if (input.TargetType.Modifier.HasEnum)
            {
                // another option for enum-"inheritance" would be dropping it altogether, and copying all the values from the
                // base enum. Adding conversion constructor from base to child type will suffice and allow to get rid
                // of those enum-inheritance matching

                // since we compare only enums here we allow slicing (because it is not slicing, just passing single int)
                match = inversedTypeMatching(ctx, input, new[] { new TypeAncestor(target, 0) }
                                             .Concat(target.Inheritance(ctx).OrderedTypeAncestorsIncludingObject)
                                             .Where(it => it.AncestorInstance.TargetType.Modifier.HasEnum), matching.WithSlicing(true));

                if (!match.IsMismatch())
                {
                    return(match);
                }
            }

            if (target.TargetsTemplateParameter)
            {
                // template parameter can have reversed inheritance defined via base-of constraints
                // todo: at this it should be already evaluated, so constraints should be surfables
                IEnumerable <IEntityInstance> base_of
                    = target.TemplateParameterTarget.Constraint.BaseOfNames.Select(it => it.Evaluated(ctx, EvaluationCall.AdHocCrossJump));

                match = inversedTypeMatching(ctx, input, new[] { new TypeAncestor(target, 0) }
                                             .Concat(base_of.Select(it => new TypeAncestor(it.Cast <EntityInstance>(), 1))), matching);

                if (!match.IsMismatch())
                {
                    return(match);
                }
            }

            return(match);
        }