예제 #1
0
        internal override void GetConcepts(ConceptSearchOptions options, ArrayBuilder <NamedTypeSymbol> concepts, Binder originalBinder, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            var searchContainers = (options & ConceptSearchOptions.SearchContainers) != 0;
            var searchUsings     = (options & ConceptSearchOptions.SearchUsings) != 0;

            // We need not check to see if the container itself is a possible
            // concept because, if it is, then it has a parent
            // container, and the below check works fine.
            if (searchContainers && _container != null)
            {
                GetConceptsInContainer(_container, concepts, originalBinder, ref useSiteDiagnostics, options);
            }

            // The above is ok if we just want to get all concepts in
            // a straight line up the scope from here to the global
            // namespace, but we also need to pull in imports too.
            if (!searchUsings)
            {
                return;
            }
            foreach (var u in GetImports(null).Usings)
            {
                // This may cause duplicate concepts, since we could
                // 'using static'-import a container already traversed in this
                // binder chain.
                GetConceptsInContainer(u.NamespaceOrType, concepts, originalBinder, ref useSiteDiagnostics, options);
            }
        }
예제 #2
0
 internal override void GetConceptInstances(ConceptSearchOptions options, ArrayBuilder <TypeSymbol> instances, Binder originalBinder, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
 {
     foreach (var parameter in _namedType.TypeParameters)
     {
         if (parameter.IsConceptWitness)
         {
             instances.Add(parameter);
         }
     }
 }
예제 #3
0
        /// <summary>
        /// Gets all concepts directly declared in a container.
        /// </summary>
        /// <param name="container">
        /// The container to visit.
        /// </param>
        /// <param name="concepts">
        /// The instance array to populate.
        /// </param>
        /// <param name="originalBinder">
        /// The call-site binder.
        /// </param>
        /// <param name="useSiteDiagnostics">
        /// The set of use-site diagnostics to populate with any errors.
        /// </param>
        /// <param name="options">
        /// The concept look-up options to use.
        /// </param>
        private void GetConceptsInContainer(NamespaceOrTypeSymbol container, ArrayBuilder <NamedTypeSymbol> concepts, Binder originalBinder, ref HashSet <DiagnosticInfo> useSiteDiagnostics, ConceptSearchOptions options)
        {
            Debug.Assert(container != null, "container being searched should not be null: this should have been checked earlier");
            var useStandaloneInstances = (options & ConceptSearchOptions.AllowStandaloneInstances) != 0;

            foreach (var member in container.GetTypeMembers())
            {
                if (!originalBinder.IsAccessible(member, ref useSiteDiagnostics, originalBinder.ContainingType))
                {
                    continue;
                }

                // Concepts can declare sub-concepts, but (for now) we don't
                // consider them.
                if (member.IsConcept || (useStandaloneInstances && member.IsStandaloneInstance))
                {
                    concepts.Add(member);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Gets all concept instances directly declared in a container.
        /// </summary>
        /// <param name="container">
        /// The container to visit.
        /// </param>
        /// <param name="instances">
        /// The instance array to populate.
        /// </param>
        /// <param name="originalBinder">
        /// The call-site binder.
        /// </param>
        /// <param name="useSiteDiagnostics">
        /// The set of use-site diagnostics to populate with any errors.
        /// </param>
        /// <param name="options">
        /// The concept look-up options to use.
        /// </param>
        private void GetConceptInstancesInContainer(NamespaceOrTypeSymbol container, ArrayBuilder <TypeSymbol> instances, Binder originalBinder, ref HashSet <DiagnosticInfo> useSiteDiagnostics, ConceptSearchOptions options)
        {
            Debug.Assert(container != null, "container being searched should not be null: this should have been checked earlier");

            foreach (var member in container.GetTypeMembers())
            {
                if (!originalBinder.IsAccessible(member, ref useSiteDiagnostics, originalBinder.ContainingType))
                {
                    continue;
                }

                // Assuming that instances don't contain sub-instances.
                if (member.IsInstance)
                {
                    instances.Add(member);
                }
                // We don't usually go into nested instances, but make an
                // exception for the inline instance struct of a class, if any.
                // This is because there would be no other way to get to it.
                else if (!member.IsConcept)
                {
                    var inline = member.GetInlineInstanceStruct();
                    if (inline != null)
                    {
                        instances.Add(inline);
                    }
                }
            }
        }
예제 #5
0
        internal virtual void LookupConceptMethodsInSingleBinder(LookupResult result, string name, int arity, ConsList <Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet <DiagnosticInfo> useSiteDiagnostics, ConceptSearchOptions coptions)
        {
            var conceptBuilder = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            GetConcepts(coptions, conceptBuilder, originalBinder, ref useSiteDiagnostics);
            var concepts = conceptBuilder.ToImmutableAndFree();

            foreach (var concept in concepts)
            {
                var methodBuilder = ArrayBuilder <MethodSymbol> .GetInstance();

                AddConceptMethods(concept, methodBuilder, name, arity, options, coptions);
                foreach (var method in methodBuilder.ToImmutableAndFree())
                {
                    SingleLookupResult resultOfThisMethod = originalBinder.CheckViability(method, arity, options, concept, diagnose, ref useSiteDiagnostics, basesBeingResolved);
                    result.MergeEqual(resultOfThisMethod);
                }
            }
        }
예제 #6
0
 /// <summary>
 /// Retrieves the list of concepts available in this
 /// binder's scope.
 /// </summary>
 /// <param name="options">
 /// The search options to use when retrieving the list.
 /// </param>
 /// <param name="concepts">
 /// The array builder to populate with concepts.
 /// </param>
 /// <param name="originalBinder">
 /// The call-site binder.
 /// </param>
 /// <param name="useSiteDiagnostics">
 /// Diagnostics set at the use-site.
 /// </param>
 internal virtual void GetConcepts(ConceptSearchOptions options, ArrayBuilder <NamedTypeSymbol> concepts, Binder originalBinder, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
 {
     // By default, binders have no concepts.
 }
예제 #7
0
        /// <summary>
        /// Adds the concept extension methods available in a concept to a
        /// candidate method list.
        /// </summary>
        /// <param name="concept">
        /// The concept we are searching for CEMs.
        /// </param>
        /// <param name="methods">
        /// The method array being populated.
        /// Any found candidate CEMs are added here.
        /// </param>
        /// <param name="nameOpt">
        /// The name of the method under lookup; may be null.
        /// </param>
        /// <param name="arity">
        /// The arity of the method under lookup.
        /// </param>
        /// <param name="options">
        /// The option set being used for this lookup.
        /// </param>
        /// <param name="conceptOptions">
        /// The concept-level options set being used for this lookup.
        /// </param>
        private void AddConceptMethods(NamedTypeSymbol concept, ArrayBuilder <MethodSymbol> methods, string nameOpt, int arity, LookupOptions options, ConceptSearchOptions conceptOptions)
        {
            var allowExtensions          = (conceptOptions & ConceptSearchOptions.NoConceptExtensions) == 0;
            var allowNonExtensions       = (conceptOptions & ConceptSearchOptions.ConceptExtensionsOnly) == 0;
            var allowStandaloneInstances = (conceptOptions & ConceptSearchOptions.AllowStandaloneInstances) != 0;

            Debug.Assert(concept != null, "cannot get methods from null concept");
            Debug.Assert(concept.IsConcept || concept.IsStandaloneInstance,
                         $"'{nameof(concept)}' is not a concept or standalone instance");
            Debug.Assert(!concept.IsStandaloneInstance || allowStandaloneInstances,
                         $"'{nameof(concept)}' is a standalone instance, which is not allowed here");
            Debug.Assert(0 <= arity, "arity cannot be negative");

            // This part is mostly copied from DoGetExtensionMethods.
            var members = nameOpt == null?concept.GetMembersUnordered() : concept.GetSimpleNonTypeMembers(nameOpt);

            foreach (var member in members)
            {
                if (member.Kind != SymbolKind.Method)
                {
                    continue;
                }
                var method = (MethodSymbol)member;

                var extensionSituationOk = method.IsConceptExtensionMethod ? allowExtensions : allowNonExtensions;
                if (!extensionSituationOk)
                {
                    continue;
                }

                var arityOk = (options & LookupOptions.AllMethodsOnArityZero) != 0 || arity == method.Arity;
                if (!arityOk)
                {
                    continue;
                }

                // @MattWindsor91 (Concept-C# 2017)
                // If we picked up this method from a concept, we need to
                // infer the specific instance we'll actually be calling.
                // Also, if the concept or standalone instance had type
                // parameters, these need to be inferred.
                var mustInferConceptParams = concept.IsConcept || concept.IsGenericType;

                // In these cases, `method` will look like
                //     `C<TC>.M<TM>(this TC x, ...)`.
                // Our prototype solution is to use a synthesised
                // symbol that looks like
                //     `M<TM, TC, implicit I>(this TC x, ...)
                //          where I : C<TC>`
                // which pushes all of the issues into the method
                // type inferrer.  When we construct the method with
                // the inferred arguments, we de-mangle the method back
                // to normal.
                //
                // This is a nice party trick, but should eventually be
                // done properly: see the commentary in
                // `GetCandidateConceptExtensionMethods`.
                var finalMethod = mustInferConceptParams
                    ? (MethodSymbol) new SynthesizedImplicitConceptMethodSymbol(method)
                    : new SynthesizedWitnessMethodSymbol(method, concept);
                methods.Add(finalMethod);
            }
        }