private static bool strictTemplateMatches(ComputationContext ctx, EntityInstance input, EntityInstance target, TypeMatching matching, out TypeMatch failMatch) { if (input.Target != target.Target) { failMatch = TypeMatch.No; return(false); } TemplateDefinition template = target.TargetTemplate; for (int i = 0; i < template.Name.Arity; ++i) { failMatch = input.TemplateArguments[i].TemplateMatchesTarget(ctx, target.TemplateArguments[i], template.Name.Parameters[i].Variance, matching); if (!failMatch.Passed) { return(false); } } failMatch = TypeMatch.Same; return(true); }
private static bool templateMatches(ComputationContext ctx, EntityInstance input, EntityInstance target, TypeMatching matching, out TypeMatch failMatch) { if (input.IsJoker || target.IsJoker) { failMatch = TypeMatch.Same; return(true); } bool matches = strictTemplateMatches(ctx, input, target, matching, out failMatch); TypeDefinition target_type = target.TargetType; if (matches || (!(matching.DuckTyping && target_type.IsInterface) && !target_type.IsProtocol)) { return(matches); } VirtualTable vtable = EntityInstanceExtension.BuildDuckVirtualTable(ctx, input, target, allowPartial: false); if (vtable == null) { return(false); } else { failMatch = TypeMatch.Same; return(true); } }
public TypeInheritance TranslateThrough(ComputationContext ctx, EntityInstance closedTemplate) { IEnumerable <TypeDefinition> traits = closedTemplate.AvailableTraits(ctx); IEnumerable <EntityInstance> minimal_parents = this.MinimalParentsWithoutObject .Concat(traits.SelectMany(it => it.Inheritance.MinimalParentsWithoutObject)) .Select(it => it.TranslateThrough(closedTemplate)) .Distinct(EntityInstance.Comparer); var dict = new Dictionary <EntityInstance, int>(EntityInstance.Comparer); foreach (TypeAncestor ancestor in this.OrderedTypeAncestorsIncludingObject .Concat(traits.SelectMany(it => it.Inheritance.OrderedTypeAncestorsIncludingObject)) .Select(it => it.TranslateThrough(closedTemplate))) { if (dict.TryGetValue(ancestor.AncestorInstance, out int dist)) { dict[ancestor.AncestorInstance] = Math.Min(dist, ancestor.Distance); } else { dict.Add(ancestor.AncestorInstance, ancestor.Distance); } } return(new TypeInheritance(this.objectType, minimal_parents, completeAncestors: dict.Select(it => new TypeAncestor(it.Key, it.Value)))); }
public static TypeMatch inversedTypeMatching(ComputationContext ctx, EntityInstance input, IEnumerable <TypeAncestor> targets, TypeMatching matching) { if (!targets.Any()) { return(TypeMatch.No); } EntityInstance target = targets.First().AncestorInstance; TypeMutability target_mutability = target.MutabilityOfType(ctx); foreach (TypeAncestor inherited_target in targets) { // please note that unlike normal type matching we reversed the types, in enum you can // pass base type as descendant! if (matchTypes(ctx, target_mutability, target.Lifetime, inherited_target.AncestorInstance, input, matching, inherited_target.Distance, out TypeMatch match)) { return(match); } } return(TypeMatch.No); }
// please remember we have to allow specialization of the function // template types (T and V) are not distinct // template type (T) and concrete type (String) are (!) distinct (specialization) // two concrete types (String and Object) are distinct (here is the example of specialization as well) public bool IsOverloadDistinctFrom(IEntityInstance other) { EntityInstance other_entity = other as EntityInstance; if (other_entity == null) { return(other.IsOverloadDistinctFrom(this)); } else if ((this.TargetsTemplateParameter && other_entity.TargetsTemplateParameter) || this.IsIdentical(other_entity)) { return(false); } else if (this.Target != other_entity.Target) { return(true); } for (int i = 0; i < this.TemplateArguments.Count; ++i) { if (this.TemplateArguments[i].IsOverloadDistinctFrom(other_entity.TemplateArguments[i])) { return(true); } } return(false); }
public override TypeMatch MatchesInput(ComputationContext ctx, EntityInstance input, TypeMatching matching) { TypeMatch match = TypeMatch.No; foreach (IEntityInstance target in this.elements) { TypeMatch m = target.MatchesInput(ctx, input, matching); if (m == TypeMatch.Same || m == TypeMatch.Substitute) { return(m); } else if (m == TypeMatch.InConversion || m == TypeMatch.AutoDereference || m == TypeMatch.ImplicitReference || m == TypeMatch.OutConversion) { match = m; } else if (!m.IsMismatch()) { throw new NotImplementedException(); } } return(match); }
internal static CallResolution Create(ComputationContext ctx, IEnumerable <TemplateArgument> templateArguments, IFunctionArgumentsProvider argumentsProvider, CallContext callContext, EntityInstance targetFunctionInstance) { // at this point we target true function (any function-like object is converted to closure already) if (!targetFunctionInstance.Target.IsFunction()) { throw new Exception("Internal error"); } List <int> arg_param_mapping = createArgParamMapping(targetFunctionInstance, callContext.MetaThisArgument, argumentsProvider.UserArguments); if (arg_param_mapping == null) { return(null); } var result = new CallResolution(ctx, templateArguments, argumentsProvider, callContext, targetFunctionInstance, arg_param_mapping, out bool success); if (success) { return(result); } else { return(null); } }
public TypeMatch TemplateMatchesInput(ComputationContext ctx, EntityInstance input, VarianceMode variance, TypeMatching matching) { // todo: this is correct but it is just a hack really, because we should check constraints // and if they are compatible we should return match if (input.TargetsTemplateParameter && this.TargetsTemplateParameter && !input.TargetTemplate.Constraints.Any() && !this.TargetTemplate.Constraints.Any()) { return(TypeMatch.Same); } matching.Position = matching.Position.Flipped(variance); switch (matching.Position) { case VarianceMode.None: return(this.IsExactlySame(input, jokerMatchesAll: true) ? TypeMatch.Same : TypeMatch.No); case VarianceMode.In: return(TypeMatcher.Matches(ctx, this, input, matching)); case VarianceMode.Out: return(TypeMatcher.Matches(ctx, input, this, matching)); } throw new NotImplementedException(); }
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); }
public IEntityInstance Evaluated(ComputationContext ctx) { if (this.Evaluation == null) { IEntityInstance eval; if (!this.IsJoker && this.Target is TemplateDefinition) { eval = this.TargetTemplate.Evaluation.Components; } else { eval = this.Target.Evaluated(ctx, EvaluationCall.AdHocCrossJump); } this.Evaluation = eval.TranslateThrough(this); if (this.Evaluation.IsJoker) { this.Aggregate = Environment.JokerInstance; } else { EntityInstance aggregate = this.Target.Evaluation.Aggregate; this.Aggregate = aggregate.TranslateThrough(this); } } return(this.Evaluation); }
private static bool matchTypes(ComputationContext ctx, TypeMutability inputMutability, Lifetime inputLifetime, EntityInstance input, EntityInstance target, TypeMatching matching, int distance, out TypeMatch match) { bool is_matched = templateMatches(ctx, input, target, matching, out TypeMatch fail_match); if (!is_matched) { match = fail_match; return(false); } // we cannot shove mutable type in disguise as immutable one, consider such scenario // user could create const wrapper over "*Object" (this is immutable type) and then create its instance // passing some mutable instance, wrapper would be still immutable despite the fact it holds mutable data // this would be disastrous when working concurrently (see more in Documentation/Mutability) bool mutability_matches; { TypeMutability target_mutability = target.MutabilityOfType(ctx); // cheapest part to compute mutability_matches = MutabilityMatches(ctx.Env.Options, inputMutability, target_mutability); // fixing mutability mismatch if (!mutability_matches && (matching.ForcedIgnoreMutability // in case when we have two value types in hand mutability does not matter, because we copy // instances and they are separate beings afterwards || (!matching.MutabilityCheckRequestByData && input.TargetType.IsValueType(ctx) && target.TargetType.IsValueType(ctx)))) { mutability_matches = true; } } if (!mutability_matches) { match = TypeMatch.Mismatched(mutability: true); return(true); } else if (matching.LifetimeCheck && matching.TargetLifetime.Outlives(matching.InputLifetime)) { match = TypeMatch.Lifetime; return(true); } else if (distance == 0 && input.Target == target.Target) { match = TypeMatch.Same; return(true); } else { match = TypeMatch.Substituted(distance); return(true); } }
internal void AddDuckVirtualTable(ComputationContext ctx, EntityInstance target, VirtualTable vtable) { if (vtable == null) { throw new Exception("Internal error"); } this.duckVirtualTables.Add(target.core, vtable); }
internal static EntityInstance CreateUnregistered(RuntimeCore core, IEntity target, TemplateTranslation translation, TypeMutability overrideMutability, Lifetime lifetime) { var instance = new EntityInstance(core, target, translation, overrideMutability, lifetime); return(instance); }
public bool IsExactlySame(INameReference other, EntityInstance translationTemplate, bool jokerMatchesAll) { if (!jokerMatchesAll) { return(this == other); } return(hasSymmetricRelation(other, (a, b) => a.IsExactlySame(b, translationTemplate, jokerMatchesAll))); }
public EvaluationInfo(IEntityInstance components, EntityInstance merged) { if (components == null || merged == null) { throw new ArgumentNullException(); } this.Components = components; this.Aggregate = merged; }
public bool IsStrictDescendantOf(ComputationContext ctx, EntityInstance ancestor) { foreach (IEntityInstance instance in this.elements) { if (!instance.IsStrictDescendantOf(ctx, ancestor)) { return(false); } } return(true); }
public static NameReference Create(TypeMutability overrideMutability, IExpression prefix, string name, IEnumerable <INameReference> arguments, EntityInstance target, bool isLocal) { var result = new NameReference(overrideMutability, prefix, BrowseMode.None, null, name, arguments?.Select(it => new TemplateArgument(it)), ExpressionReadMode.ReadRequired, isRoot: false); if (target != null) { result.Binding.Set(new[] { new BindingMatch(target, isLocal) }); } return(result); }
public static TemplateTranslation Create(EntityInstance instance, IEntityInstance argument) { if (instance.Target.Name.Parameters.Count != 1) { throw new ArgumentException(); } Dictionary <TemplateParameter, IEntityInstance> dict = instance.Translation.table.ToDictionary(it => it.Key, it => it.Value); dict[instance.Target.Name.Parameters[0]] = argument; return(new TemplateTranslation(instance.Target, dict)); }
private CallResolution(ComputationContext ctx, IEnumerable <TemplateArgument> templateArguments, IFunctionArgumentsProvider argumentsProvider, CallContext callContext, EntityInstance targetFunctionInstance, List <int> argParamMapping, out bool success) { success = true; this.MetaThisArgument = callContext.MetaThisArgument; this.TargetFunctionInstance = targetFunctionInstance; this.argumentsProvider = argumentsProvider; if (this.IsExtendedCall) { this.ExtensionsArguments = new[] { this.MetaThisArgument } }
internal static ParameterType Create(ComputationContext ctx, FunctionParameter param, IEntityInstance objectInstance, EntityInstance targetFunctionInstance) { IEntityInstance elem_instance = translateFunctionElement(param.ElementTypeName.Evaluation.Components, objectInstance, targetFunctionInstance); IEntityInstance type_instance = translateFunctionElement(param.TypeName.Evaluation.Components, objectInstance, targetFunctionInstance); Lifetime param_lifetime = param.Evaluation.Aggregate.Lifetime; elem_instance = elem_instance.Rebuild(ctx, param_lifetime, deep: false); type_instance = type_instance.Rebuild(ctx, param_lifetime, deep: false); return(new ParameterType(elementTypeInstance: elem_instance, typeInstance: type_instance)); }
public IEntityInstance TranslateThrough(ref bool translated, TemplateTranslation translation) { // consider: // Coll<T,A> implements IColl<A> // and then you have Coll<Int,String> (closedTemplate) -- so how does IColl looks now? // IColl<String> (since A maps to String) // and we compute it here // or let's say we have type Foo<T> and one of its methods returns T // then we have instance Foo<String> (closedTemplate), what T is then? (String) if (translation == null || translation == TemplateTranslation.Empty) { return(this); } if (this.TargetsTemplateParameter) { if (translation.Translate(this.TemplateParameterTarget, out IEntityInstance trans)) { if (!this.IsIdentical(trans)) { translated = true; } return(trans); } return(this); } else { TemplateTranslation combo_translation = TemplateTranslation.Translated(this.Translation, translation, ref translated); EntityInstance result = this.Target.GetInstance(this.OverrideMutability, combo_translation, this.Lifetime); return(result); } }
public override TypeMatch MatchesInput(ComputationContext ctx, EntityInstance input, TypeMatching matching) { TypeMatch match = TypeMatch.No; foreach (IEntityInstance target in this.elements) { TypeMatch m = target.MatchesInput(ctx, input, matching); if (m.IsMismatch()) { return(m); } else if (match.IsMismatch()) { match = m; } else if (match != m) { return(TypeMatch.No); } } return(match); }
protected EntityInstance createAggregate(ComputationContext ctx, bool hasReference, bool hasPointer, IEnumerable <EntityInstance> dereferencedInstances, IEnumerable <FunctionDefinition> members, bool partialVirtualTables) { this.aggregate = TypeBuilder.Create(AutoName.Instance.CreateNew("Aggregate")) .With(members) .SetModifier(EntityModifier.Protocol); aggregate.AttachTo(this); this.aggregate.Evaluated(ctx, EvaluationCall.AdHocCrossJump); EntityInstance aggregate_instance = this.aggregate.InstanceOf; foreach (EntityInstance instance in dereferencedInstances) { EntityInstanceExtension.BuildDuckVirtualTable(ctx, instance, aggregate_instance, allowPartial: partialVirtualTables); } if (hasReference || hasPointer) { aggregate_instance = ctx.Env.Reference(aggregate_instance, TypeMutability.None, viaPointer: hasPointer); } return(aggregate_instance); }
public static ConstraintMatch ArgumentsMatchConstraintsOf(ComputationContext ctx, EntityInstance closedTemplate) { if (closedTemplate == null || closedTemplate.IsJoker) { return(ConstraintMatch.Yes); } return(ArgumentsMatchConstraintsOf(ctx, closedTemplate.Target.Name.Parameters, closedTemplate)); }
public static ConstraintMatch ArgumentsMatchConstraintsOf(ComputationContext ctx, IEnumerable <TemplateParameter> templateParameters, EntityInstance closedTemplate) { if (templateParameters.Count() != closedTemplate.TemplateArguments.Count) { return(ConstraintMatch.UndefinedTemplateArguments); } foreach (Tuple <TemplateParameter, IEntityInstance> param_arg in templateParameters .SyncZip(closedTemplate.TemplateArguments)) { ConstraintMatch match = param_arg.Item2.ArgumentMatchesParameterConstraints(ctx, closedTemplate, param_arg.Item1); if (match != ConstraintMatch.Yes) { return(match); } } return(ConstraintMatch.Yes); }
public static bool TryGetSingleType(this INameReference @this, out NameReference nameReference, out EntityInstance typeInstance) { nameReference = @this as NameReference; if (nameReference == null) { typeInstance = null; return(false); } else { typeInstance = nameReference.Evaluation.Components.Cast <EntityInstance>(); return(true); } }
public IEnumerable <EntityInstance> TranslateBaseOf(EntityInstance closedTemplate) { return(BaseOfNames.Select(it => it.Binding.Match.Instance) .Select(it => it.TranslateThrough(closedTemplate))); }
protected override void compute(ComputationContext ctx) { IEntityInstance eval = EntityInstanceUnion.Create(Elements.Select(it => it.Evaluation.Components)); // we need to get common members bool has_reference = false; bool has_pointer = false; var dereferenced_instances = new List <EntityInstance>(); List <FunctionDefinition> members = null; foreach (EntityInstance ____instance in this.Elements.Select(it => it.Evaluation.Aggregate)) { if (ctx.Env.DereferencedOnce(____instance, out IEntityInstance __instance, out bool via_pointer)) { if (via_pointer) { has_pointer = true; } else { has_reference = true; } } EntityInstance instance = __instance.Cast <EntityInstance>(); dereferenced_instances.Add(instance); if (members == null) { members = instance.TargetType.NestedFunctions .Where(f => !f.IsAnyConstructor() && f.Parameters.All(it => !it.IsOptional)) .ToList(); } else { foreach (FunctionDefinition m in members.ToArray()) { bool found = false; foreach (FunctionDefinition func in instance.TargetType.NestedFunctions) { // todo: maybe some day handle optionals if (func.IsAnyConstructor() || func.Parameters.Any(it => it.IsOptional)) { continue; } if (FunctionDefinitionExtension.IsSame(ctx, m, func, instance)) { found = true; break; } } if (!found) { members.Remove(m); } } } } EntityInstance aggregate_instance = createAggregate(ctx, has_reference, has_pointer, dereferenced_instances, members, partialVirtualTables: false); this.Evaluation = new EvaluationInfo(eval, aggregate_instance); }
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); }
public NameReference CreateNameReference(IExpression prefix, EntityInstance targetInstance, bool isLocal) { return(NameReference.Create(prefix, this.Name, this.Parameters.Select(it => NameReference.Create(it.Name)), targetInstance, isLocal)); }