/// <summary> /// Tries to look up symbols inside a witness type parameter. /// <para> /// This lookup checks all of the concepts this witness implements /// to see if any contain a viable method matching the symbol. /// </para> /// <para> /// This lookup approach only works for methods and properties, and /// returns members whose parents are type parameters. We rely on /// later stages to detect this and resolve it back to a proper /// statement. /// </para> /// </summary> /// <param name="witness"> /// The type witness into which we are looking. /// </param> /// <param name="result"> /// The lookup result to populate. /// </param> /// <param name="name"> /// The name of the member being looked-up. /// </param> /// <param name="arity"> /// The arity of the member being looked up. /// </param> /// <param name="basesBeingResolved"> /// The set of bases being resolved. /// </param> /// <param name="options"> /// The lookup options in effect. /// </param> /// <param name="originalBinder"> /// The top-level binder. /// </param> /// <param name="diagnose"> /// Whether or not we are diagnosing. /// </param> /// <param name="useSiteDiagnostics"> /// Diagnostics set at the use-site. /// </param> internal void LookupSymbolsInWitness( TypeParameterSymbol witness, LookupResult result, string name, int arity, ConsList <Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(witness.IsConceptWitness); var concepts = witness.ProvidedConcepts; if (concepts.IsDefaultOrEmpty) { return; } foreach (var c in concepts) { var members = GetCandidateMembers(c, name, options, originalBinder); foreach (var member in members) { switch (member.Kind) { case SymbolKind.Method: var method = (MethodSymbol)member; // Suppose our witness is W : C<A>, and this finds C<A>.M(x). // We need to return that we found W.M(x), but W is a type // parameter! While we can handle this later on in binding, // the main issue is changing C<A> to W, for which we use // a synthesized method symbol. var witnessMethod = new SynthesizedWitnessMethodSymbol(method, witness); SingleLookupResult resultOfThisMethod = originalBinder.CheckViability(witnessMethod, arity, options, witness, diagnose, ref useSiteDiagnostics, basesBeingResolved); result.MergeEqual(resultOfThisMethod); break; case SymbolKind.Property: var prop = (PropertySymbol)member; var witnessProp = new SynthesizedWitnessPropertySymbol(prop, witness); SingleLookupResult resultOfThisProp = originalBinder.CheckViability(witnessProp, arity, options, witness, diagnose, ref useSiteDiagnostics, basesBeingResolved); result.MergeEqual(resultOfThisProp); break; // We don't allow other types to be fields of a witness } } } }
/// <summary> /// Tries to look up symbols inside a witness type parameter. /// <para> /// This lookup checks all of the concepts this witness implements /// to see if any contain a viable method matching the symbol. /// </para> /// <para> /// This lookup approach only works for methods, and returns a /// method whose parent is a type parameter. We rely on later /// binder stages to detect this and resolve it back to a proper /// statement. /// </para> /// </summary> /// <param name="witness"> /// The type witness into which we are looking. /// </param> /// <param name="result"> /// The lookup result to populate. /// </param> /// <param name="name"> /// The name of the member being looked-up. /// </param> /// <param name="arity"> /// The arity of the member being looked up. /// </param> /// <param name="basesBeingResolved"> /// The set of bases being resolved. /// </param> /// <param name="options"> /// The lookup options in effect. /// </param> /// <param name="originalBinder"> /// The top-level binder. /// </param> /// <param name="diagnose"> /// Whether or not we are diagnosing. /// </param> /// <param name="useSiteDiagnostics"> /// Diagnostics set at the use-site. /// </param> internal void LookupSymbolsInWitness( TypeParameterSymbol witness, LookupResult result, string name, int arity, ConsList <Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(witness.IsConceptWitness); // Concepts are just interfaces, so we look at every possible // interface this witness has been constrained to implement. foreach (var iface in witness.AllEffectiveInterfacesNoUseSiteDiagnostics) { if (!iface.IsConcept) { continue; } // We're assuming that the above handles inheritance for us. // This may be a mistake. var members = GetCandidateMembers(iface, name, options, originalBinder); foreach (var member in members) { // Don't bother trying to resolve non-methods: // concepts can't have them, and we only have shims for // dealing with methods later on anyway. if (member.Kind != SymbolKind.Method) { continue; } var method = member as MethodSymbol; Debug.Assert(method != null); // Suppose our witness is W : C<A>, and this finds C<A>.M(x). // We need to return that we found W.M(x), but W is a type // parameter! While we can handle this later on in binding, // the main issue is changing C<A> to W, for which we use // a synthesized method symbol. var witnessMethod = new SynthesizedWitnessMethodSymbol(method, witness); SingleLookupResult resultOfThisMember = originalBinder.CheckViability(witnessMethod, arity, options, witness, diagnose, ref useSiteDiagnostics, basesBeingResolved); result.MergeEqual(resultOfThisMember); } } }