提交 a73e0141 编写于 作者: E Evan Hauck 提交者: Jared Parsons

Fix a few issues that were blocking VS dogfooding

上级 d978315f
......@@ -5650,10 +5650,19 @@ private static void CopyExtensionMethodArguments(AnalyzedArguments originalArgum
var members = ArrayBuilder<Symbol>.GetInstance();
bool wasError;
Symbol symbol = GetSymbolOrMethodOrPropertyGroup(lookupResult, node, rightName, arity, members, diagnostics, out wasError);
// PROTOTYPE: This might not be true for extension classes - LookupExtensionMembers returns other kinds of members.
Debug.Assert((object)symbol == null);
Debug.Assert(members.Count > 0);
methodGroup.PopulateWithExtensionMethods(left, members.SelectAsArray(s_toMethodSymbolFunc), typeArguments, lookupResult.Kind);
if ((object)symbol != null)
{
// This can happen when a non-extension method was found on the type (say, .Count()),
// and an extension property was found (say, .Count). For now, always prefer the non-extension method.
// PROTOTYPE: Evalulate the above statement, and figure out what to do in the face of mixed-member-kind lookups in general
// (e.g. when both property and method extensions are found with the same name, and both are applicable)
Debug.Assert(!members.Any());
}
else
{
Debug.Assert(members.Count > 0);
methodGroup.PopulateWithExtensionMethods(left, members.SelectAsArray(s_toMethodSymbolFunc), typeArguments, lookupResult.Kind);
}
members.Free();
}
......@@ -6731,7 +6740,10 @@ private ErrorPropertySymbol CreateErrorPropertySymbol(ImmutableArray<PropertySym
methodGroup.Methods, methodGroup.TypeArguments, analyzedArguments, methodGroup.Receiver,
result, ref useSiteDiagnostics, isMethodGroupConversion, allowRefOmittedArguments,
inferWithDynamic: inferWithDynamic, allowUnexpandedForm: allowUnexpandedForm);
return new MethodGroupResolution(methodGroup, null, result, analyzedArguments, methodGroup.ResultKind, sealedDiagnostics);
// The caller does not expect analyzedArguments to be consumed (it frees it after it's done), so make a copy to consume (for the result).
var argumentCopy = AnalyzedArguments.GetInstance();
CopyExtensionMethodArguments(analyzedArguments, argumentCopy); // PROTOTYPE: Figure out if a copy is needed (this is not an extension method).
return new MethodGroupResolution(methodGroup, null, result, argumentCopy, methodGroup.ResultKind, sealedDiagnostics);
}
}
......
......@@ -542,6 +542,7 @@ private void EmitArgListOperator(BoundArgListOperator expression)
}
}
private void EmitArgument(BoundExpression argument, RefKind refKind)
{
if (refKind == RefKind.None)
......@@ -551,7 +552,12 @@ private void EmitArgument(BoundExpression argument, RefKind refKind)
else
{
var temp = EmitAddress(argument, AddressKind.Writeable);
Debug.Assert(temp == null, "passing args byref should not clone them into temps");
// PROTOTYPE: Resolve the commented-out assert.
// temporaries are allowed in the specific case of emitting a receiver for an extension class instance member extending a struct.
// This situation did not occur before, since `ref this` is not allowed on old-style extension methods (but is default for extension class).
// Disable the assert for now, until we resolve what we specifically want to do here.
//Debug.Assert(temp == null, "passing args byref should not clone them into temps");
FreeOptTemp(temp);
}
}
......
......@@ -1500,23 +1500,26 @@ private void CheckModelAndSyntaxNodeToSpeculate(CSharpSyntaxNode syntax)
if (lookupResult.IsMultiViable)
{
foreach (MethodSymbol extensionMethod in lookupResult.Symbols)
// PROTOTYPE: Improve this filtering
foreach (var extensionMember in lookupResult.Symbols)
{
if (extensionMethod.MethodKind == MethodKind.ReducedExtension)
if (extensionMember.Kind == SymbolKind.Method)
{
// PROTOTYPE: Fix this somehow. We might have to do partial type inference to get
// the receiverType to line up right, and do receiver inference on extension class methods.
var receiverType = (TypeSymbol)container;
var rereduced = extensionMethod.UnreduceExtensionMethod().ReduceExtensionMethod(receiverType);
if (rereduced != null)
var extensionMethod = (MethodSymbol)extensionMember;
if (extensionMethod.MethodKind == MethodKind.ReducedExtension)
{
results.Add(rereduced);
// PROTOTYPE: Fix this somehow. We might have to do partial type inference to get
// the receiverType to line up right, and do receiver inference on extension class methods.
var receiverType = (TypeSymbol)container;
var rereduced = extensionMethod.UnreduceExtensionMethod().ReduceExtensionMethod(receiverType);
if (rereduced != null)
{
results.Add(rereduced);
}
continue;
}
}
else
{
results.Add(extensionMethod);
}
results.Add(extensionMember);
}
}
......@@ -3028,7 +3031,7 @@ public ILocalSymbol GetDeclaredSymbol(CatchDeclarationSyntax catchDeclaration, C
if ((conversion.ConversionKind == ConversionKind.MethodGroup) && conversion.IsExtensionMethod)
{
var symbol = conversion.SymbolOpt;
Debug.Assert((object)symbol != null && symbol.MethodKind == MethodKind.ReducedExtension);
Debug.Assert((object)symbol != null && (symbol.MethodKind == MethodKind.ReducedExtension || symbol.IsInExtensionClass));
symbols = ImmutableArray.Create<Symbol>(symbol);
resultKind = conversion.ResultKind;
}
......@@ -4128,10 +4131,8 @@ internal static ImmutableArray<MethodSymbol> GetReducedAndFilteredMethodGroupSym
constructedMethod = method;
}
if ((object)receiverType != null)
if ((object)receiverType != null && constructedMethod.MethodKind == MethodKind.ReducedExtension)
{
// PROTOTYPE: Figure this out
Debug.Assert(constructedMethod.MethodKind == MethodKind.ReducedExtension);
constructedMethod = constructedMethod.UnreduceExtensionMethod().ReduceExtensionMethod(receiverType);
if ((object)constructedMethod == null)
{
......
......@@ -104,7 +104,11 @@ public override TypeSymbol ReceiverType
{
get
{
return _typeMap.SubstituteType(_reducedFrom.Parameters[0].Type).Type;
// Note: Do not alpha rename the type (_typeMap.SubstituteType).
// This is because upon reduction of Foo<T>(this T t) into T.Foo<T'>(), we "reduced it"
// using the receiver type of the *original* (static) method symbol type parameter.
// Typemapping to the alpha-renamed type parameter causes an impossible recursion.
return _reducedFrom.Parameters[0].Type;
}
}
......
......@@ -230,7 +230,7 @@ internal override void GetExtensionMembers(ArrayBuilder<Symbol> members, string
{
var original = underlyingMethod.UnreduceExtensionMethod();
var retargeted = this.RetargetingTranslator.Retarget(original);
var reduced = retargeted.ReduceExtensionMethod();
var reduced = retargeted.ReduceExtensionMethod(); // PROTOTYPE: Specify the receiver type here.
Debug.Assert((object)reduced != null);
Debug.Assert(reduced.IsDefinition);
members.Add(reduced);
......
......@@ -1118,7 +1118,6 @@ public override Symbol GetUnderlyingMember(Symbol symbol)
underlyingMembersMap = _underlyingMembersMap;
}
// PROTOTYPE: Strip generic constructions off of symbol?
Symbol cachedResult;
if (underlyingMembersMap.TryGetValue(symbol, out cachedResult))
{
......@@ -1157,7 +1156,15 @@ public override Symbol GetUnderlyingMember(Symbol symbol)
else
{
var constructedFrom = method.ConstructedFrom;
result = new UnreducedExtensionMethodSymbol(constructedFrom);
var resultMethod = new UnreducedExtensionMethodSymbol(constructedFrom);
if (method != constructedFrom)
{
result = resultMethod.Construct(method.TypeArguments);
}
else
{
result = resultMethod;
}
}
// PROTOTYPE: Generics/construction of result? (probably put in Create method)
break;
......
......@@ -229,7 +229,8 @@ public override int GetHashCode()
private sealed class UnreducedExtensionMethodThisParameterSymbol : SynthesizedParameterSymbol
{
public UnreducedExtensionMethodThisParameterSymbol(UnreducedExtensionMethodSymbol containingMethod) :
base(containingMethod, containingMethod.ContainingType.ExtensionClassType, 0, RefKind.None)
base(containingMethod, containingMethod.ContainingType.ExtensionClassType, 0,
containingMethod.ContainingType.ExtensionClassType.IsValueType ? RefKind.Ref : RefKind.None)
{
}
......
......@@ -68,7 +68,15 @@ public UnreducedExtensionPropertySymbol(PropertySymbol unreducedFrom)
public override ImmutableArray<CustomModifier> TypeCustomModifiers => _unreducedFrom.TypeCustomModifiers;
internal override Cci.CallingConvention CallingConvention => _unreducedFrom.CallingConvention;
internal override Cci.CallingConvention CallingConvention
{
get
{
var originalCallingConvention = _unreducedFrom.CallingConvention;
Debug.Assert((originalCallingConvention & Cci.CallingConvention.HasThis) != 0);
return originalCallingConvention & ~Cci.CallingConvention.HasThis;
}
}
internal override bool HasSpecialName => _unreducedFrom.HasSpecialName;
......
......@@ -449,6 +449,91 @@ static void Main()
parseOptions: parseOptions);
}
[Fact]
public void BuiltinExtensions()
{
var text = @"
using System;
extension class MathExt : double
{
public double Cos => Math.Cos(this);
}
extension class IntMathExt : int
{
public double Abs => Math.Abs(this);
}
struct Derp
{
public void Foo()
{
}
}
static class Program
{
static void Main()
{
new Derp().Foo();
var x = 2.0.Cos;
// round it a bit so we don't have to deal with precision.
// x should be somewhere around -0.41614683654
Console.Write((int)(x * 10000));
Console.Write(' ');
Console.Write(1.Abs);
Console.Write((-1).Abs);
}
}
";
CompileAndVerify(
source: text,
additionalRefs: additionalRefs.Concat(new[] { MscorlibRef_v46 }),
expectedOutput: "-4161 11",
parseOptions: parseOptions);
}
[Fact]
public void CountProperty()
{
var text = @"
using System;
using System.Linq;
using System.Collections.Generic;
extension class EnumExt : IEnumerable<int>
{
public int Size => this.Count();
}
extension class StrExt : string
{
public string JoinStr<T>(List<T> stuff)
{
return string.Join(this, stuff);
}
}
static class Program
{
static void Main()
{
Console.Write(new[]{1,2}.Size);
Func<List<string>, string> joinn = "", "".JoinStr;
Console.Write(joinn(new List<string> { ""hello"", ""world"" }));
}
}
";
CompileAndVerify(
source: text,
additionalRefs: additionalRefs.Concat(new[] { MscorlibRef_v46 }),
expectedOutput: "2hello, world",
parseOptions: parseOptions);
}
[Fact]
public void DuckDiscovery()
{
......
......@@ -306,7 +306,7 @@ public class C
TestRoundTrip(symbols, compilation);
}
[Fact(Skip = "PROTOTYPE: Extension Everything breaks this, due to reduced method symbols having a receiver type dependent on type parameters")]
[Fact]
public void TestExtensionMethodReferences()
{
var source = @"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册