|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Basic.Reference.Assemblies;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class MethodTypeInferenceTests : OverloadResolutionTestBase
{
[Fact]
public void TestMethodTypeInference()
{
// TODO: Fill in the remaining holes in this test, marked with NYT.
TestOverloadResolutionWithDiff(
@"
using System.Collections.Generic;
interface Con<in CON> {}
interface Cov<out COV> {}
interface Inv<INV> {}
delegate void DCon<in DCON>();
delegate void DCov<out DCOV>();
delegate void DInv<DINV>();
class Animal {}
class Mammal : Animal {}
class Tiger : Mammal {}
delegate int FInt<FINT>(FINT p1);
delegate FUNC0 Func0<FUNC0>();
delegate FUNC1R Func1<FUNC1A, FUNC1R>(FUNC1A p1);
class Class<CLASS> { public enum Enum {} }
class Derived<DER> : Class<DER>, Con<DER>, Inv<DER>, Cov<DER> {}
struct Struct<STRUCT> : Con<STRUCT>, Inv<STRUCT>, Cov<STRUCT> {}
interface Interface<INTERFACE> : Con<INTERFACE>, Inv<INTERFACE>, Cov<INTERFACE> {}
class C
{
void N1<T1>(FInt<T1> p1){}
void N32<R32>(Func0<R32> p1){}
void N32<A32, R32>(A32 p1, Func1<A32, R32> p2){}
int M32() { return 1; }
int M32(string s) { return 1; }
void N41<T41>(Con<T41> p1, ref T41 p2) {}
void N42<T42>(Con<T42> p1, ref T42[] p2) {}
void N431<T431>(Con<T431> p1, ref Class<T431> p2) {}
void N432<T432>(Con<T432> p1, ref Struct<T432> p2) {}
void N4321<T4321>(Con<T4321> p1, ref Struct<T4321>? p2) {}
void N4322<T4322>(Con<T4322> p1, ref Class<T4322>.Enum p2) {}
void N4331<T4331>(Con<T4331> p1, ref DCov<T4331> p2) {}
void N4332<T4332>(Con<T4332> p1, ref DCon<T4332> p2) {}
void N4333<T4333>(Con<T4333> p1, ref DInv<T4333> p2) {}
void N4341<T4341>(Con<T4341> p1, ref Cov<T4341> p2) {}
void N4342<T4342>(Con<T4342> p1, ref Con<T4342> p2) {}
void N4343<T4343>(Con<T4343> p1, ref Inv<T4343> p2) {}
void N51<T51>(T51 p1, T51 p2) {}
void N5211<T5211>(T5211 p1, T5211[] p2) {}
void N5212<T5212>(Con<T5212> p1, Struct<T5212>[] p2){}
void N5231A<T5231A>(T5231A p1, IEnumerable<T5231A> p2) {}
void N5231B<T5231B>(T5231B p1, ICollection<T5231B> p2) {}
void N5231C<T5231C>(T5231C p1, IList<T5231C> p2) {}
void N5231D<T5231D>(T5231D p1, IReadOnlyCollection<T5231D> p2) {}
void N5231E<T5231E>(T5231E p1, IReadOnlyList<T5231E> p2) {}
void N5232A<T5232A>(IEnumerable<T5232A> p1) {}
void N5232B<T5232B>(ICollection<T5232B> p1) {}
void N5232C<T5232C>(IList<T5232C> p1) {}
void N5232D<T5232D>(IReadOnlyCollection<T5232D> p1) {}
void N5232E<T5232E>(IReadOnlyList<T5232E> p1) {}
void N5321<T5321>(Con<T5321> p1, Class<T5321> p2) {}
void N5322<T5322>(Con<T5322> p1, Struct<T5322> p2) {}
void N5323<T5323>(Con<T5323> p1, Struct<T5323>? p2) {}
void N5331<T5331>(T5331 p1, DCov<T5331> p2) {}
void N5332<T5332>(ref T5332 p1, DCon<T5332> p2) {}
void N5333<T5333>(Con<T5333> p1, DInv<T5333> p2) {}
void N5341<T5341>(T5341 p1, Cov<T5341> p2) {}
void N5342<T5342>(ref T5342 p1, Con<T5342> p2) {}
void N5343<T5343>(Con<T5343> p1, Inv<T5343> p2) {}
void N541<T541>(Con<T541> p1, Class<T541> p2) {}
void N61<T61>(ref T61 p1, Con<T61> p2) {}
void N6211<T6211>(ref T6211 p1, Con<T6211[]> p2) {}
void N6212<T6212>(Con<T6212> p1, Con<Struct<T6212>[]> p2) {}
void N6231<T6231>(T6231 p1, Con<T6231[]> p2) {}
void N6232<T6232>(Con<Struct<T6232>[]> p1) {}
void N631<T631>(Con<T631> p1, Con<Class<T631>> p2) {}
void N632<T632>(Con<T632> p1, Con<Struct<T632>> p2) {}
void N6321<T6321>(Con<T6321> p1, Con<Struct<T6321>?> p2) {}
void N6331<T6331>(ref T6331 p1, Con<DCov<T6331>> p2) {}
void N6332<T6332>(T6332 p1, Con<DCon<T6332>> p2) {}
void N6333<T6333>(Con<T6333> p1, Con<DInv<T6333>> p2) {}
void N6341<T6341>(ref T6341 p1, Con<Cov<T6341>> p2) {}
void N6342<T6342>(T6342 p1, Con<Con<T6342>> p2) {}
void N6343<T6343>(Con<T6343> p1, Con<Inv<T6343>> p2) {}
void N64<T64>(Con<T64> p1, Con<Derived<T64>> p2) {}
void N6511<T6511>(ref T6511 p1, Con<Derived<T6511>> p2) {}
void N6512<T6512>(T6512 p1, Con<Derived<T6512>> p2) {}
void N6513<T6513>(Con<T6513> p1, Con<Derived<T6513>> p2) {}
void N6531<T6531>(ref T6531 p1, Con<Interface<T6531>> p2) {}
void N6532<T6532>(T6532 p1, Con<Interface<T6532>> p2) {}
void N6533<T6533>(Con<T6533> p1, Con<Interface<T6533>> p2) {}
void N71<A71, R71)(A71 p1, Func1<A71, R71> p2) {}
Class<T71> M71<T71>(T71 p1) { return null; }
Tiger tiger;
Mammal mammal;
Animal animal;
Con<Tiger> conTiger;
Inv<Tiger> invTiger;
Cov<Tiger> covTiger;
Con<Mammal> conMammal;
Cov<Mammal> covMammal;
Inv<Mammal> invMammal;
Cov<Animal> covAnimal;
Inv<Animal> invAnimal;
Con<Animal> conAnimal;
DCon<Mammal> dconMammal;
DCov<Mammal> dcovMammal;
DInv<Mammal> dinvMammal;
Inv<Class<Mammal>> invClsMammal;
Inv<Class<Mammal[]>> invClsMammalArr;
Mammal[] mammalArr;
Struct<Mammal>[] structMammalArr;
Con<Mammal[]> conMammalArr;
Con<Struct<Mammal>[]> conStructMammalArr;
Class<Mammal> classMammal;
Derived<Mammal> derivedMammal;
Interface<Mammal> interfaceMammal;
Struct<Mammal> structMammal;
Con<Class<Mammal>> conClassMammal;
Con<Struct<Mammal>> conStructMammal;
Con<Struct<Mammal>?> conNullableStructMammal;
Con<DCov<Mammal>> conDCovMammal;
Con<DCon<Mammal>> conDConMammal;
Con<DInv<Mammal>> conDInvMammal;
Con<Cov<Mammal>> conCovMammal;
Con<Con<Mammal>> conConMammal;
Con<Inv<Mammal>> conInvMammal;
Struct<Mammal>? nullableStructMammal;
Class<Mammal>.Enum classMammalEnum;
string str;
void M()
{
// Method type inference test plan
//
// Method type inference is complicated and there are a lot of possibilities to test
//
// features not yet implemented are marked NYI
// features not yet tested are marked NYT
//
// Strategies:
//
// When attempting to prove that an exact bound has been made, make an upper bound of Animal
// and an exact bound of Mammal. The parameter should be resolved as Mammal, even though Mammal is more specific.
//
// When attempting to prove that a lower bound has been made, make a lower bound of of Animal and
// a lower bound of Mammal. The parameter should be resolved as Animal; the Mammal bound is allowed to
// relax and become Animal.
//
// When attempting to prove that an upper bound has been made, make an exact bound of Tiger and
// an upper bound of Mammal. The parameter should be resolved as Tiger; the Mammal bound is allowed
// to become Tiger.
// 1 explicit lambda parameter to delegate parameter type (exact)
N1((double x)=>123); //-C.N1<double>(FInt<double>)
// 2 inferred lambda return type inference (NYI)
// 2.1 to void delegate (NYI)
// 2.2 to non-void delegate (NYI)
// 3 method group return type inference
// 3.1 to void delegate (NYT)
// 3.2 to non void delegate
N32(M32); //-C.N32<int>(Func0<int>)
N32(str, M32); //-C.N32<string, int>(string, Func1<string, int>)
// 4 exact inference
// 4.1 from any type S to method type parameter T (exact)
// 4.2 from array S[] to array T[]
// 4.2.1 where ranks match (exact)
// 4.2.2 where ranks do not match (no inference made) (NYT)
// 4.3 from constructed type
// 4.3.1 from class C<S> to class C<T> (exact)
// 4.3.2 from struct C<S> to struct C<T> (exact)
// 4.3.2.1 from nullable N<S> to N<T> (exact)
// 4.3.2.2 from enum C<S>.E to enum C<T>.E (exact)
// 4.3.3 from delegate C<S> to C<T>
// 4.3.3.1 covariant (exact)
// 4.3.3.2 contravariant (exact)
// 4.3.3.3 invariant (exact)
// 4.3.4 from interface C<S> to interface C<T>
// 4.3.4.1 covariant (exact)
// 4.3.4.2 contravariant (exact)
// 4.3.4.3 invariant (exact)
N41(conAnimal, ref mammal); //-C.N41<Mammal>(Con<Mammal>, ref Mammal)
N42(conAnimal, ref mammalArr); //-C.N42<Mammal>(Con<Mammal>, ref Mammal[])
N431(conAnimal, ref classMammal); //-C.N431<Mammal>(Con<Mammal>, ref Class<Mammal>)
N432(conAnimal, ref structMammal); //-C.N432<Mammal>(Con<Mammal>, ref Struct<Mammal>)
N4321(conAnimal, ref nullableStructMammal); //-C.N4321<Mammal>(Con<Mammal>, ref Struct<Mammal>?)
N4322(conAnimal, ref classMammalEnum); //-C.N4322<Mammal>(Con<Mammal>, ref Class<Mammal>.Enum)
N4331(conAnimal, ref dcovMammal); //-C.N4331<Mammal>(Con<Mammal>, ref DCov<Mammal>)
N4332(conAnimal, ref dconMammal); //-C.N4332<Mammal>(Con<Mammal>, ref DCon<Mammal>)
N4333(conAnimal, ref dinvMammal); //-C.N4333<Mammal>(Con<Mammal>, ref DInv<Mammal>)
N4341(conAnimal, ref covMammal); //-C.N4341<Mammal>(Con<Mammal>, ref Cov<Mammal>)
N4342(conAnimal, ref conMammal); //-C.N4342<Mammal>(Con<Mammal>, ref Con<Mammal>)
N4343(conAnimal, ref invMammal); //-C.N4343<Mammal>(Con<Mammal>, ref Inv<Mammal>)
// 5 lower bound inference
// 5.1 from any type to method type parameter T (lower)
// 5.2 from array S[]
// 5.2.1 to array T[] of same rank
// 5.2.1.1 of reference type (lower)
// 5.2.1.2 of value type (exact)
// 5.2.2 to array T[] of different rank (no inference made) (NYT)
// 5.2.3 from 1-d array S[] to IEnumerable<T>, ICollection<T>, IList<T>, IReadOnlyList<T> and IReadOnlyCollection<T>
// 5.2.3.1 of reference type (lower)
// 5.2.3.2 of value type (exact)
// 5.3 from constructed type to matching constructed type
// 5.3.1 from class C<S> to C<T> (exact)
// 5.3.2 from struct C<S> to C<T> (exact)
// 5.3.2.1 nullable N<S> to N<T> (exact)
// 5.3.3 from delegate C<S> to C<T>
// 5.3.3.1 covariant (lower)
// 5.3.3.2 contravariant (upper)
// 5.3.3.3 invariant (exact)
// 5.3.4 from interface C<S> to C<T>
// 5.3.4.1 covariant (lower)
// 5.3.4.2 contravariant (upper)
// 5.3.4.3 invariant (exact)
// 5.4 base class
// 5.4.1 from class D with base class C<S> to C<T> (exact)
// 5.4.2 from type parameter D with effective base class C<S> to C<T> (exact) (NYI)
// 5.4.3 from type parameter D with effective base class E that has base class C<S> to C<T> (exact) (NYI)
N51(animal, mammal); //-C.N51<Animal>(Animal, Animal)
N5211(animal, mammalArr); //-C.N5211<Animal>(Animal, Animal[])
N5212(conAnimal, structMammalArr); //-C.N5212<Mammal>(Con<Mammal>, Struct<Mammal>[])
N5231A(animal, mammalArr); //-C.N5231A<Animal>(Animal, System.Collections.Generic.IEnumerable<Animal>)
N5231B(animal, mammalArr); //-C.N5231B<Animal>(Animal, System.Collections.Generic.ICollection<Animal>)
N5231C(animal, mammalArr); //-C.N5231C<Animal>(Animal, System.Collections.Generic.IList<Animal>)
N5231D(animal, mammalArr); //-C.N5231D<Animal>(Animal, System.Collections.Generic.IReadOnlyCollection<Animal>)
N5231E(animal, mammalArr); //-C.N5231E<Animal>(Animal, System.Collections.Generic.IReadOnlyList<Animal>)
N5232A(structMammalArr); //-C.N5232A<Struct<Mammal>>(System.Collections.Generic.IEnumerable<Struct<Mammal>>)
N5232B(structMammalArr); //-C.N5232B<Struct<Mammal>>(System.Collections.Generic.ICollection<Struct<Mammal>>)
N5232C(structMammalArr); //-C.N5232C<Struct<Mammal>>(System.Collections.Generic.IList<Struct<Mammal>>)
N5232D(structMammalArr); //-C.N5232D<Struct<Mammal>>(System.Collections.Generic.IReadOnlyCollection<Struct<Mammal>>)
N5232E(structMammalArr); //-C.N5232E<Struct<Mammal>>(System.Collections.Generic.IReadOnlyList<Struct<Mammal>>)
N5321(conAnimal, classMammal); //-C.N5321<Mammal>(Con<Mammal>, Class<Mammal>)
N5322(conAnimal, structMammal); //-C.N5322<Mammal>(Con<Mammal>, Struct<Mammal>)
N5323(conAnimal, nullableStructMammal); //-C.N5323<Mammal>(Con<Mammal>, Struct<Mammal>?)
N5331(animal, dcovMammal); //-C.N5331<Animal>(Animal, DCov<Animal>)
N5332(ref tiger, dconMammal); //-C.N5332<Tiger>(ref Tiger, DCon<Tiger>)
N5333(conAnimal, dinvMammal); //-C.N5333<Mammal>(Con<Mammal>, DInv<Mammal>)
N5341(animal, covMammal); //-C.N5341<Animal>(Animal, Cov<Animal>)
N5342(ref tiger, conMammal); //-C.N5342<Tiger>(ref Tiger, Con<Tiger>)
N5343(conAnimal, invMammal); //-C.N5343<Mammal>(Con<Mammal>, Inv<Mammal>)
N541(conAnimal, derivedMammal); //-C.N541<Mammal>(Con<Mammal>, Class<Mammal>)
// 5.5 base interface
// in all cases, base interface must be 'unique'. (NYT)
// 5.5.1 from class D with base interface C<S> to C<T>
// 5.5.1.1 covariant (lower)
// 5.5.1.2 contravariant (upper)
// 5.5.1.3 invariant (exact)
// 5.5.2 from struct D with base interface C<S> to C<T>
// 5.5.2.1 covariant (lower)
// 5.5.2.2 contravariant (upper)
// 5.5.2.3 invariant (exact)
// 5.5.3 from interface D with base interface C<S> to C<T>
// 5.5.3.1 covariant (lower)
// 5.5.3.2 contravariant (upper)
// 5.5.3.3 invariant (exact)
// Just re-use the methods from section 5.3.4
N5341(animal, derivedMammal); //-C.N5341<Animal>(Animal, Cov<Animal>)
N5342(ref tiger, derivedMammal); //-C.N5342<Tiger>(ref Tiger, Con<Tiger>)
N5343(conAnimal, derivedMammal); //-C.N5343<Mammal>(Con<Mammal>, Inv<Mammal>)
N5341(animal, structMammal); //-C.N5341<Animal>(Animal, Cov<Animal>)
N5342(ref tiger, structMammal); //-C.N5342<Tiger>(ref Tiger, Con<Tiger>)
N5343(conAnimal, structMammal); //-C.N5343<Mammal>(Con<Mammal>, Inv<Mammal>)
N5341(animal, interfaceMammal); //-C.N5341<Animal>(Animal, Cov<Animal>)
N5342(ref tiger, interfaceMammal); //-C.N5342<Tiger>(ref Tiger, Con<Tiger>)
N5343(conAnimal, interfaceMammal); //-C.N5343<Mammal>(Con<Mammal>, Inv<Mammal>)
// 5.5.4 from type parameter D with effective base class E that implements interface C<S> to C<T> (NYI)
// 5.5.4.1 covariant (lower)(NYI)
// 5.5.4.2 contravariant (upper)(NYI)
// 5.5.4.3 invariant (exact)(NYI)
// 5.5.5 from type parameter D with effective interface set member C<S> to C<T> (NYI)
// 5.5.5.1 covariant (lower)(NYI)
// 5.5.5.2 contravariant (upper)(NYI)
// 5.5.5.3 invariant (exact)(NYI)
// 5.5.6 from type parameter D with effective interface set member E that inherits from C<S> to C<T> (NYI)
// 5.5.6.1 covariant (lower)(NYI)
// 5.5.6.2 contravariant (upper)(NYI)
// 5.5.6.3 invariant (exact)(NYI)
// 6 upper bound inference
// 6.1 from any type S to method type parameter T (upper)
// 6.2 to array T[]
// 6.2.1 from array S[] of same rank
// 6.2.1.1 of reference type (upper)
// 6.2.1.2 of value type (exact)
// 6.2.2 from array S[] of different rank (no inference made) (NYT)
// 6.2.3 from IEnumerable<S>, ICollection<S> or IList<S> to one-d array T[]
// 6.2.3.1 of reference type (upper)
// 6.2.3.2 of value type (exact)
// 6.3 from constructed type to matching constructed type
// 6.3.1 from class C<S> to C<T> (exact)
// 6.3.2 from struct C<S> to C<T> (exact)
// 6.3.2.1 nullable N<S> to N<T> (exact)
// 6.3.3 from delegate C<S> to C<T>
// 6.3.3.1 covariant (upper)
// 6.3.3.2 contravariant (lower)
// 6.3.3.3 invariant (exact)
// 6.3.4 from interface C<S> to C<T>
// 6.3.4.1 covariant (upper)
// 6.3.4.2 contravariant (lower)
// 6.3.4.3 invariant (exact)
// 6.4 from class C<S> to class D with base class C<T> (exact)
// 6.5 base interface - in all cases, base interface must be 'unique'.
// 6.5.1 from interface C<S> to class D with base interface C<T>
// 6.5.1.1 covariant (upper)
// 6.5.1.2 contravariant (lower)
// 6.5.1.3 invariant (exact)
// 6.5.2 from interface C<S> to struct D with base interface C<T> (NYT)
// These are unusual cases because here method type inference will succeed but will
// always produce a result that is not applicable. If you have an upper bound inference
// because you are inferring from Con<Struct<S>> to Con<I<T>> where Struct<S> implements I<S>
// then we make the upper bound inference from I<S> to I<T>. If that succeeds then applicability
// checking will fail, because Con<any value type> is not convertible to Con<any reference type>.
// In order to verify that type inference is succeeding here we'll have to make some error cases
// and see if we're getting 'not applicable' errors vs 'type inference failed' errors.
// 6.5.2.1 covariant (upper)(NYT)
// 6.5.2.2 contravariant (lower)(NYT)
// 6.5.2.3 invariant (exact)(NYT)
// 6.5.3 from interface C<S> to interface D with base interface C<T>
// 6.5.3.1 covariant (upper)
// 6.5.3.2 contravariant (lower)
// 6.5.3.3 invariant (exact)
N61(ref tiger, conMammal); //-C.N61<Tiger>(ref Tiger, Con<Tiger>)
N6211(ref tiger, conMammalArr); //-C.N6211<Tiger>(ref Tiger, Con<Tiger[]>)
N6212(conAnimal, conStructMammalArr); //-C.N6212<Mammal>(Con<Mammal>, Con<Struct<Mammal>[]>)
N6231(tiger, (Con<IEnumerable<Mammal>>)null); //-C.N6231<Mammal>(Mammal, Con<Mammal[]>)
N6231(tiger, (Con<IList<Mammal>>)null); //-C.N6231<Mammal>(Mammal, Con<Mammal[]>)
N6231(tiger, (Con<IReadOnlyList<Mammal>>)null); //-C.N6231<Mammal>(Mammal, Con<Mammal[]>)
N6231(tiger, (Con<IReadOnlyCollection<Mammal>>)null); //-C.N6231<Mammal>(Mammal, Con<Mammal[]>)
N6232((Con<IEnumerable<Struct<Mammal>>>)null); //-C.N6232<Mammal>(Con<Struct<Mammal>[]>)
N6232((Con<IList<Struct<Mammal>>>)null); //-C.N6232<Mammal>(Con<Struct<Mammal>[]>)
N6232((Con<IReadOnlyList<Struct<Mammal>>>)null); //-C.N6232<Mammal>(Con<Struct<Mammal>[]>)
N6232((Con<IReadOnlyCollection<Struct<Mammal>>>)null); //-C.N6232<Mammal>(Con<Struct<Mammal>[]>)
N631(conAnimal, conClassMammal); //-C.N631<Mammal>(Con<Mammal>, Con<Class<Mammal>>)
N632(conAnimal, conStructMammal); //-C.N632<Mammal>(Con<Mammal>, Con<Struct<Mammal>>)
N6321(conAnimal, conNullableStructMammal); //-C.N6321<Mammal>(Con<Mammal>, Con<Struct<Mammal>?>)
N6331(ref tiger, conDCovMammal); //-C.N6331<Tiger>(ref Tiger, Con<DCov<Tiger>>)
N6332(animal, conDConMammal); //-C.N6332<Animal>(Animal, Con<DCon<Animal>>)
N6333(conAnimal, conDInvMammal); //-C.N6333<Mammal>(Con<Mammal>, Con<DInv<Mammal>>)
N6341(ref tiger, conCovMammal); //-C.N6341<Tiger>(ref Tiger, Con<Cov<Tiger>>)
N6342(animal, conConMammal); //-C.N6342<Animal>(Animal, Con<Con<Animal>>)
N6343(conAnimal, conInvMammal); //-C.N6343<Mammal>(Con<Mammal>, Con<Inv<Mammal>>)
N64(conAnimal, conClassMammal); //-C.N64<Mammal>(Con<Mammal>, Con<Derived<Mammal>>)
N6511(ref tiger, conCovMammal); //-C.N6511<Tiger>(ref Tiger, Con<Derived<Tiger>>)
N6512(animal, conConMammal); //-C.N6512<Animal>(Animal, Con<Derived<Animal>>)
N6513(conAnimal, conInvMammal); //-C.N6513<Mammal>(Con<Mammal>, Con<Derived<Mammal>>)
N6531(ref tiger, conCovMammal); //-C.N6531<Tiger>(ref Tiger, Con<Interface<Tiger>>)
N6532(animal, conConMammal); //-C.N6532<Animal>(Animal, Con<Interface<Animal>>)
N6533(conAnimal, conInvMammal); //-C.N6533<Mammal>(Con<Mammal>, Con<Interface<Mammal>>)
// 7 Additional interesting scenarios:
// 7.1 Method type inference where the argument is a method group containing a generic method that also
// needs method type inference:
N71(1, M71); //-C.N71<int, Class<int>>(int, Func1<int, Class<int>>)
}
}
");
}
[Fact]
public void TestLambdaTypeInference()
{
TestOverloadResolutionWithDiff(
@"
interface IE<out COV> {}
delegate R F<out R> ();
delegate R F<in A, out R> (A a);
delegate R F<in A1, in A2, out R> (A1 a1, A2 a2);
class Customer { public string Name; public int ID; }
class Order { public decimal Total; public int? CustomerID; }
class L<T> { public void D<R>(F<T, R> f){} }
class C
{
IE<T> Where<T>(IE<T> s, F<T, bool> f) { return null; }
IE<R> Select<A, R>(IE<A> s, F<A, R> f) { return null; }
IE<R> Join<I, O, K, R>(IE<I> inner, IE<O> outer, F<I, K> innerKey, F<O, K> outerKey, F<I, O, R> selector) { return null; }
T Apply<T>(F<T> f) { return f(); }
T Apply<T>(F<T> f1, F<T> f2) { return f1(); }
T Apply<T>(params F<T>[] fs) { return fs[0](); }
static int GetID(Customer c) { return c.ID; }
IE<Customer> customers;
IE<Order> orders;
void M()
{
object x1 = Where(customers, c=>c.Name == null);
//-C.Where<Customer>(IE<Customer>, F<Customer, bool>)
object x2 = Select(customers, c=>c.Name);
//-C.Select<Customer, string>(IE<Customer>, F<Customer, string>)
object x3 = Join(customers, orders, c=>c.ID, o=>o.CustomerID, (c,o)=>o.Total);
//-C.Join<Customer, Order, int?, decimal>(IE<Customer>, IE<Order>, F<Customer, int?>, F<Order, int?>, F<Customer, Order, decimal>)
object x4 = Select(customers, c=>{ if (c.Name == string.Empty) return null; else return c.Name; });
//-C.Select<Customer, string>(IE<Customer>, F<Customer, string>)
object x5 = Apply(()=>new Customer());
//-C.Apply<Customer>(F<Customer>)
object x6 = Apply(()=>new Customer(), ()=>{while(true){}});
//-C.Apply<Customer>(F<Customer>, F<Customer>)
object x7 = Apply(()=>1, ()=>2, ()=>{while(true){}});
//-C.Apply<int>(params F<int>[])
// Make sure that overload resolution and type inference involving method group conversions works:
object x8 = Select(customers, GetID);
//-C.Select<Customer, int>(IE<Customer>, F<Customer, int>)
(new L<int>()).D(x=>123.4);
//-L<int>.D<double>(F<int, double>)
}
}
");
}
[Fact]
public void TestMethodTypeInferenceErrors()
{
var source = @"
class C
{
delegate R F<out R>();
static T Apply<T>(F<T> f) { return f(); }
static void M()
{
Apply(delegate { while (true) { } });
}
}
";
CreateCompilation(source).VerifyDiagnostics(
// (8,7): error CS0411: The type arguments for method 'C.Apply<T>(C.F<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
// Apply(delegate { while (true) { } });
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Apply").WithArguments("C.Apply<T>(C.F<T>)").WithLocation(8, 7));
}
[Fact, WorkItem(578362, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/578362")]
public void TypeInferenceDynamicByRef()
{
string source = @"
class C
{
static void Main()
{
dynamic d = null;
Goo(ref d);
}
static void Goo<T>(ref T[] x)
{
}
}
";
CreateCompilationWithMscorlib40AndSystemCore(source, new[] { CSharpRef }).VerifyEmitDiagnostics(
// (7,9): error CS0411: The type arguments for method 'C.Goo<T>(ref T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly.
// Goo(ref d);
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Goo").WithArguments("C.Goo<T>(ref T[])"));
}
[WorkItem(541810, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541810")]
[Fact]
public void TestMethodTypeInferenceWhenFixedParameterIsOpenGenericType()
{
var source = @"
using System.Collections.Generic;
class Test
{
static void Goo<V>(V x)
{
I<V> i = null;
var y = new List<string>();
i.method(x, y);
}
static void Main()
{
Goo(1);
}
interface I<T>
{
void method<U>(T x, List<U> y);
}
}";
CompileAndVerify(source).VerifyDiagnostics();
}
[WorkItem(541811, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541811")]
[Fact]
public void TestMethodTypeInferenceWhenFixedParameterIsOpenGenericType2()
{
var source = @"
using System.Collections.Generic;
class Test
{
static void Main()
{
Test.Run(1, 2);
}
public static void Run<T, U>(T t, U u)
{
I<U> i = new Outer<U, T>();
i.Goo(u, new List<string>());
}
interface I<A>
{
void Goo<B>(A a, List<B> y);
}
class Outer<P, Q> : I<P>
{
void I<P>.Goo<S>(P p, List<S> y)
{
}
}
}";
CreateCompilation(source).VerifyDiagnostics();
}
[Fact]
public void TestMethodTypeInferenceWhenFixedParameterIsOpenGenericType03()
{
var source = @"
class Test
{
class C<T>
{
public static void M<U>(T t, U u)
{
// The inference is a bit tricky here because there
// are two distinct things both called 'U'. There is the
// 'U' of the caller, and the 'U' of the callee; they are
// different types. We must not reason 'the method here
// is C<U>.M<U>(U, U) so let's infer U' from both arguments.
// Rather, we must say that this is C<U1>.M<U2>(U1, U2) and
// infer U2 alone.
C<U>.M(u, 123);
// For example, the call in Main below will call
// C<string>.M<double>. That method will call
// C<double>.M<int>, which will then call
// C<int>.M<int>.
}
}
static void Main()
{
C<string>.M<double>(null, 1.0);
}
}";
CompileAndVerify(source).VerifyDiagnostics();
}
[WorkItem(541887, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541887")]
[Fact()]
public void Bug8785_1()
{
// Right now Roslyn allows this syntax; the missing type arguments are ignored and we
// do method type inference as though they were not there at all.
// This should be illegal; we could produce an error at parse time or semantic
// analysis time.
var source = @"
class Program
{
static void Main(string[] args)
{
var s = Goo<>(123, 345);
}
public static int Goo<T, U>(T t, U u)
{
return 1;
}
}
";
CreateCompilation(source).VerifyDiagnostics(
// (6,17): error CS0305: Using the generic method 'Program.Goo<T, U>(T, U)' requires 2 type arguments
// var s = Goo<>(123, 345);
Diagnostic(ErrorCode.ERR_BadArity, "Goo<>").WithArguments("Program.Goo<T, U>(T, U)", "method", "2"));
}
[Fact]
public void Bug50782_1()
{
string source = """
using System.Diagnostics.CodeAnalysis;
#nullable enable
interface IOperation<T>
{ }
public class StringOperation : IOperation<string?>
{ }
public class C
{
static void Main()
{
TestA(new StringOperation(), out string? discardA);
TestA(new StringOperation(), out string? _);
TestA(new StringOperation(), out var _);
TestA(new StringOperation(), out _);
TestB(new StringOperation(), out string? discardB);
TestB(new StringOperation(), out string? _);
TestB(new StringOperation(), out var _);
TestB(new StringOperation(), out _);
TestC<string?>(out string? discardC);
TestC<string?>(out string? _);
TestC<string?>(out var _);
TestC<string?>(out _);
TestD<string?>(out string? discardD);
TestD<string?>(out string? _);
TestD<string?>(out var _);
TestD<string?>(out _);
TestE(out string? discardE);
TestE(out var discardEVar);
TestE(out string? _);
TestE(out var _);
TestE(out _);
TestF(out string? discardF);
TestF(out string? _);
}
static void TestA<T>(IOperation<T> operation, [MaybeNull] out T result) => result = default;
static void TestB<T>(IOperation<T> operation, out T result) => result = default!;
static void TestC<T>([MaybeNull] out T result) => result = default;
static void TestD<T>(out T result) => result = default!;
static void TestE([MaybeNull] out string result) => result = default;
static void TestF(out string result) => result = "";
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
// out _
foreach (var discardOut in GetDiscardIdentifiers(tree))
{
CheckDiscard(model, discardOut, "System.String?");
}
// out T _, out var _, out T? _
foreach (var discardDecl in GetDiscardDesignations(tree))
{
CheckDiscard(model, discardDecl, "System.String?");
}
}
[Fact]
public void Bug50782_2()
{
string source = """
#nullable enable
interface IOperation<T>
{ }
public class StringOperation : IOperation<string>
{ }
public class C
{
static void Main()
{
TestA(new StringOperation(), out string discardA);
TestA(new StringOperation(), out string _);
TestA(new StringOperation(), out var _);
TestA(new StringOperation(), out _);
TestB(out string discardB);
TestB(out string _);
TestB<string>(out var discardVarB);
TestB<string>(out var _);
TestB<string>(out _);
TestC(out var _);
TestC(out _);
}
static void TestA<T>(IOperation<T> operation, out T result) => result = default!;
static void TestB<T>(out T result) => result = default!;
static void TestC(out string result) => result = "";
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
// out _
foreach (var discardOut in GetDiscardIdentifiers(tree))
{
CheckDiscard(model, discardOut, "System.String!");
}
// out var _, out T _
foreach (var discardDecl in GetDiscardDesignations(tree))
{
CheckDiscard(model, discardDecl, "System.String!");
}
}
[Fact]
public void Bug50782_3()
{
string source = """
#nullable enable
interface IOperation<T>
{ }
public class StringOperation : IOperation<string>
{ }
public class C
{
static void Main()
{
TestA(new StringOperation(), out string? discardA);
TestA(new StringOperation(), out string? _);
TestC(out string? discardC);
TestC(out string? _);
}
static void TestA<T>(IOperation<T> operation, out T result) => result = default!;
static void TestC(out string result) => result = "";
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
// out _
foreach (var discardOut in GetDiscardIdentifiers(tree))
{
CheckDiscard(model, discardOut, "System.String?");
}
// out var _, out T _
foreach (var discardDecl in GetDiscardDesignations(tree))
{
CheckDiscard(model, discardDecl, "System.String?");
}
}
[Fact]
public void Bug50782_4()
{
string source = """
#nullable enable
void M((string, string?) tuple)
{
(_, _) = tuple;
(string _, string _) = tuple;
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(new[] {
// (2,6): warning CS8321: The local function 'M' is declared but never used
// void M((string, string?) tuple)
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(2, 6),
// (5,28): warning CS8600: Converting null literal or possible null value to non-nullable type.
// (string _, string _) = tuple;
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "tuple").WithLocation(5, 28)
});
}
private static void CheckDiscard(SemanticModel model, DiscardDesignationSyntax discard, string type)
{
Assert.Null(model.GetDeclaredSymbol(discard));
Assert.Null(model.GetTypeInfo(discard).Type);
Assert.Null(model.GetSymbolInfo(discard).Symbol);
var declaration = (DeclarationExpressionSyntax)discard.Parent;
Assert.Equal(type, model.GetTypeInfo(declaration).Type.ToTestDisplayString(includeNonNullable: true));
Assert.Null(model.GetSymbolInfo(declaration).Symbol);
}
private static void CheckDiscard(SemanticModel model, IdentifierNameSyntax discard, string type)
{
Assert.Null(model.GetDeclaredSymbol(discard));
var discardSymbol = (IDiscardSymbol)model.GetSymbolInfo(discard).Symbol;
Assert.Equal(type, discardSymbol.Type.ToTestDisplayString(includeNonNullable: true));
Assert.Equal(type, model.GetTypeInfo(discard).Type.ToTestDisplayString(includeNonNullable: true));
}
private static IEnumerable<DiscardDesignationSyntax> GetDiscardDesignations(SyntaxTree tree)
{
return tree.GetRoot().DescendantNodes().OfType<DiscardDesignationSyntax>();
}
private static IEnumerable<IdentifierNameSyntax> GetDiscardIdentifiers(SyntaxTree tree)
{
return tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(i => i.Identifier.ContextualKind() == SyntaxKind.UnderscoreToken);
}
[WorkItem(541887, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541887")]
[Fact]
public void Bug8785_2()
{
// We should produce a parse error here, but *not* a semantic analysis error
// stating that type "" could not be found.
var source = @"
class Program
{
static void Main(string[] args)
{
var s = Goo<int, >(123, 345);
}
public static int Goo<T, U>(T t, U u)
{
return 1;
}
}
";
CreateCompilation(source).VerifyDiagnostics(
// (6,26): error CS1031: Type expected
// var s = Goo<int, >(123, 345);
Diagnostic(ErrorCode.ERR_TypeExpected, ">"),
// CONSIDER: we would prefer not to report this cascading diagnostic.
// (6,33): error CS1503: Argument 2: cannot convert from 'int' to '?'
// var s = Goo<int, >(123, 345);
Diagnostic(ErrorCode.ERR_BadArgType, "345").WithArguments("2", "int", "?"));
}
[WorkItem(542591, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542591")]
[Fact]
public void Bug9877()
{
// No NRE
var source = @"
class Program
{
public static void M<T>(System.Func<T> f)
{
M(E.A);
}
}
";
CreateCompilation(source).VerifyDiagnostics(
// (6,11): error CS0103: The name 'E' does not exist in the current context
Diagnostic(ErrorCode.ERR_NameNotInContext, "E").WithArguments("E"));
}
[WorkItem(9145, "http://vstfdevdiv:8080/DevDiv_Projects/Roslyn/_workitems/edit/9145")]
[Fact]
public void Bug9145()
{
string source = @"
using System;
using System.Collections.Generic;
public interface IParser<TSource, TSource1> { }
public class ParserQueryContext<TSource, TSource1, T> : IParser<TSource, TSource1> { }
public static partial class ParserExtensions
{
public static IParser<TSource, TResult> Select<TSource, TIntermediate, TResult>(this IParser<TSource, TIntermediate> parser, Func<TIntermediate, TResult> selector) { return null; }
public static ParserQueryContext<TParseSource, TParseResult, TResult> Select<TParseSource, TParseResult, TSource, TResult>(this ParserQueryContext<TParseSource, TParseResult, TSource> source, Func<TSource, TResult> selector) { return null; }
public static IParser<TSource, IEnumerable<TResult>> Exactly<TSource, TResult>(this IParser<TSource, TResult> parser, int count) { return null; }
public static IParser<TSource, TResult> Where<TSource, TResult>(this IParser<TSource, TResult> parser, Func<TResult, bool> predicate) { return null; }
public static IParser<TSource, IEnumerable<TResult>> OneOrMore<TSource, TResult>(this IParser<TSource, TResult> parser) { return null; }
public static IParser<TSource, IEnumerable<TResult>> OneOrMore<TSource, TResult>(this IParser<TSource, TResult> parser, IParser<TSource, TResult> separator) { return null; }
public static IParser<TSource, TResult> SelectMany<TSource, TFirstResult, TCollection, TResult>(this IParser<TSource, TFirstResult> parser, Func<TFirstResult, IEnumerable<TCollection>> collectionSelector, Func<TFirstResult, TCollection, TResult> resultSelector) { return null; }
public static IParser<TSource, TResult> SelectMany<TSource, TFirstResult, TSecondResult, TResult>(this IParser<TSource, TFirstResult> parser, Func<TFirstResult, IParser<TSource, TSecondResult>> parserSelector, Func<TFirstResult, TSecondResult, TResult> resultSelector) { return null; }
public static IParser<TSource, TResult> Not<TSource, TNotResult, TResult>(this IParser<TSource, TResult> parser, IParser<TSource, TNotResult> notParser) { return null; }
public static IParser<TSource, IEnumerable<TResult>> NoneOrMore<TSource, TResult>(this IParser<TSource, TResult> parser) { return null; }
public static IParser<TSource, IEnumerable<TResult>> And<TSource, TResult>(this IParser<TSource, IEnumerable<TResult>> parser, IParser<TSource, IEnumerable<TResult>> nextParser) { return null; }
public static IParser<TSource, IEnumerable<TResult>> And<TSource, TResult>(this IParser<TSource, IEnumerable<TResult>> parser, IParser<TSource, TResult> nextParser) { return null; }
public static IParser<TSource, IEnumerable<TResult>> And<TSource, TResult>(this IParser<TSource, TResult> parser, IParser<TSource, IEnumerable<TResult>> nextParser) { return null; }
public static IParser<TSource, IEnumerable<TResult>> And<TSource, TResult>(this IParser<TSource, TResult> parser, IParser<TSource, TResult> nextParser) { return null; }
public static IParser<TSource, IList<TResult>> ToList<TSource, TResult>(this IParser<TSource, IEnumerable<TResult>> parser) { return null; }
public static IEnumerable<TResult> Parse<TSource, TResult>(this IEnumerable<TSource> source, IParser<TSource, TResult> parser) { return null; }
public static IEnumerable<TResult> Parse<TSource, TResult>(this IEnumerable<TSource> source, Func<ParserQueryContext<TSource, TSource, IParser<TSource, TSource>>, ParserQueryContext<TSource, TSource, IParser<TSource, TResult>>> grammarSelector) { return null; }
public static IEnumerable<TResult> Parse<TSource, TResult>(this IEnumerable<TSource> source, Func<ParserQueryContext<TSource, TSource, IParser<TSource, TSource>>, ParserQueryContext<TSource, TSource, IParser<TSource, IEnumerable<TResult>>>> grammarSelector) { return null; }
}
class Program
{
static void Main(string[] args)
{
var arr = new byte[] { 0xff, 0xff, 0x00, 0xc9, 0xff, 0xfe, 0xfe, 0xff, 0xff };
var result = arr./*<bind>*/Parse/*</bind>*/(parser =>
from next in parser
let val1 = next.Where(v => v == 0xff)
let val2 = next.Where(v => v == 0xfe)
let end = val1.Exactly(2)
let packet = from _1 in val1.OneOrMore()
from r in next.Not(val2).And(next.Not(end).NoneOrMore())
from _2 in end
select r
select packet.ToList()
);
}
}
";
CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics();
}
[WorkItem(543691, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543691")]
[Fact]
public void Bug()
{
string source = @"
class Program
{
static void M<T>(T? t1, T t2) where T : struct
{
System.Console.WriteLine(typeof(T));
}
static void Main()
{
M((char?)null, (int)0);
}
}
";
CreateCompilation(source).VerifyDiagnostics();
}
[WorkItem(649800, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/649800")]
[Fact]
public void InferringVoid()
{
// inference off a void method should fail
var source = @"
public class Test
{
static void M<T>(T t) { }
static void M1<T>(ref T t) { }
public static void Main()
{
M(Main());
M1(ref Main());
}
}
";
CreateCompilation(source).VerifyDiagnostics(
// (8,9): error CS0411: The type arguments for method 'Test.M<T>(T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
// M(Main());
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("Test.M<T>(T)"),
// (9,16): error CS1510: A ref or out argument must be an assignable variable
// M1(ref Main());
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "Main()")
);
}
[WorkItem(717264, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/717264")]
[Fact]
public void SubstitutedMethod()
{
var source = @"
using System;
public class C<T>
{
public void M<U>(Func<T, U> f1, Func<long, U> f2) { }
void Test(C<char> c)
{
c.M(x => x, y => 'a');
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var syntax = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
var method = (IMethodSymbol)model.GetSymbolInfo(syntax).Symbol;
Assert.Equal(SpecialType.System_Char, method.TypeArguments.Single().SpecialType);
Assert.Equal("void C<System.Char>.M<System.Char>(System.Func<System.Char, System.Char> f1, System.Func<System.Int64, System.Char> f2)", method.ToTestDisplayString());
}
[WorkItem(717264, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/717264")]
[Fact]
public void SubstitutedMethod_Params()
{
var source = @"
using System;
public class C<T>
{
public void M<U>(Func<T, U> f1, Func<long, U> f2, params int[] a) { }
void Test(C<char> c)
{
c.M(x => x, y => 'a', 1, 2, 3);
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var syntax = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
var method = (IMethodSymbol)model.GetSymbolInfo(syntax).Symbol;
Assert.Equal(SpecialType.System_Char, method.TypeArguments.Single().SpecialType);
Assert.Equal("void C<System.Char>.M<System.Char>(System.Func<System.Char, System.Char> f1, System.Func<System.Int64, System.Char> f2, params System.Int32[] a)", method.ToTestDisplayString());
}
[WorkItem(8712, "https://github.com/dotnet/roslyn/issues/8712")]
[Fact]
public void EnumerableJoinIntellisenseForParameterTypesShouldPopOutAutoComplete_1()
{
var source = @"
using System.Collections.Generic;
using System.Linq;
public class Book
{
public int AuthorId { get; set; }
public string Title { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Test
{
public static void NoIntellisenseInEnumerableJoin()
{
IEnumerable<Book> books = null;
IEnumerable<Author> authors = null;
var test = books.Join(authors, b => b. // !!Fails here!!
}
}";
var compilation = CreateCSharpCompilation(source);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var book = (IdentifierNameSyntax)tree.GetRoot().DescendantTokens().Last(t => t.Text == "b").Parent;
var bookType = model.GetTypeInfo(book).Type;
Assert.Equal("Book", bookType.Name);
}
[WorkItem(8712, "https://github.com/dotnet/roslyn/issues/8712")]
[Fact]
public void EnumerableJoinIntellisenseForParameterTypesShouldPopOutAutoComplete_2()
{
var source = @"
using System.Collections.Generic;
using System.Linq;
public class Book
{
public int AuthorId { get; set; }
public string Title { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Test
{
public static void NoIntellisenseInEnumerableJoin()
{
IEnumerable<Book> books = null;
IEnumerable<Author> authors = null;
var test = books.Join(authors, b => b.AuthorId, a => a. // !!Fails here!!
}
}";
var compilation = CreateCSharpCompilation(source);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var author = (IdentifierNameSyntax)tree.GetRoot().DescendantTokens().Last(t => t.Text == "a").Parent;
var authorType = model.GetTypeInfo(author).Type;
Assert.Equal("Author", authorType.Name);
}
[WorkItem(8712, "https://github.com/dotnet/roslyn/issues/8712")]
[Fact]
public void EnumerableJoinIntellisenseForParameterTypesShouldPopOutAutoComplete_3()
{
var source = @"
using System.Collections.Generic;
using System.Linq;
public class Book
{
public int AuthorId { get; set; }
public string Title { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Test
{
public static void NoIntellisenseInEnumerableJoin()
{
IEnumerable<Book> books = null;
IEnumerable<Author> authors = null;
var test = books.Join(authors, b => b.AuthorId, a => a.Id, (bookResult, authorResult) => new { bookResult, authorResult });
}
}";
var compilation = CreateCSharpCompilation(source).VerifyDiagnostics();
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var bookResult = (IdentifierNameSyntax)tree.GetRoot().DescendantTokens().Last(t => t.Text == "bookResult").Parent;
var bookResultType = model.GetTypeInfo(bookResult).Type;
Assert.Equal("Book", bookResultType.Name);
var authorResult = (IdentifierNameSyntax)tree.GetRoot().DescendantTokens().Last(t => t.Text == "authorResult").Parent;
var authorResultType = model.GetTypeInfo(authorResult).Type;
Assert.Equal("Author", authorResultType.Name);
}
}
}
|