Skip to content
This repository has been archived by the owner on Aug 24, 2022. It is now read-only.

Commit

Permalink
Checkpoint work on supporting 'ref this' for structs.
Browse files Browse the repository at this point in the history
  • Loading branch information
kg committed Jun 24, 2012
1 parent 7f0daf8 commit 723cc1d
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 7 deletions.
40 changes: 36 additions & 4 deletions JSIL/Transforms/IntroduceVariableReferences.cs
Expand Up @@ -31,6 +31,22 @@ public class IntroduceVariableReferences : JSAstVisitor {
return false; return false;
} }


protected JSVariable GetReferentVariable (JSPassByReferenceExpression pbr) {
JSVariable referentVariable;
JSExpression referent;

if (!JSReferenceExpression.TryMaterialize(JSIL, pbr.Referent, out referent)) {
if (JSReferenceExpression.TryDereference(JSIL, pbr.Referent, out referent)) {
referentVariable = referent as JSVariable;
return referentVariable;
} else
return null;
}

referentVariable = referent as JSVariable;
return referentVariable;
}

protected JSVariable GetConstructedReference (JSPassByReferenceExpression pbr) { protected JSVariable GetConstructedReference (JSPassByReferenceExpression pbr) {
JSVariable referentVariable; JSVariable referentVariable;
JSExpression referent; JSExpression referent;
Expand Down Expand Up @@ -60,12 +76,20 @@ public class IntroduceVariableReferences : JSAstVisitor {


// If the variable does not match the one in the dictionary, it is a constructed // If the variable does not match the one in the dictionary, it is a constructed
// reference to a parameter. // reference to a parameter.
if (!referentVariable.Equals(Variables[referentVariable.Identifier])) { var theVariable = Variables[referentVariable.Identifier];
if (!referentVariable.Equals(theVariable)) {


// If the parameter is a reference, we don't care about it. // If the parameter is a reference, we don't care about it.
if (Variables[referentVariable.Identifier].IsReference) if (theVariable.IsReference) {
return null; // Unless it's the 'this' variable...
else if (theVariable.IsThis) {
// But we handle that separately.
return referentVariable;
} else {
return null;
}

} else
return referentVariable; return referentVariable;
} }


Expand Down Expand Up @@ -185,6 +209,14 @@ public class IntroduceVariableReferences : JSAstVisitor {
continue; continue;
} }


// For 'ref this', we need to replace each individual expression, because we can't
// rename the this-variable.
if (cr.IsThis) {
var refThis = JSIL.NewReference(Variables["this"]);
fn.ReplaceChildRecursive(r, refThis);
continue;
}

var parameter = (from p in fn.Parameters var parameter = (from p in fn.Parameters
where p.Identifier == cr.Identifier where p.Identifier == cr.Identifier
select p).FirstOrDefault(); select p).FirstOrDefault();
Expand Down
24 changes: 22 additions & 2 deletions JSIL/Transforms/StaticAnalysis/EmulateStructAssignment.cs
Expand Up @@ -76,9 +76,29 @@ public class EmulateStructAssignment : JSAstVisitor {
value = ((JSReferenceExpression)value).Referent; value = ((JSReferenceExpression)value).Referent;


var valueType = value.GetActualType(TypeSystem); var valueType = value.GetActualType(TypeSystem);
var cte = value as JSChangeTypeExpression;
var cast = value as JSCastExpression;

TypeReference originalType;
int temp;

if (cte != null) {
originalType = cte.Expression.GetActualType(TypeSystem);
} else if (cast != null) {
originalType = cast.Expression.GetActualType(TypeSystem);
} else {
originalType = null;
}


if (!TypeUtil.IsStruct(valueType)) if (originalType != null) {
return false; originalType = TypeUtil.FullyDereferenceType(originalType, out temp);

if (!TypeUtil.IsStruct(valueType) && !TypeUtil.IsStruct(originalType))
return false;
} else {
if (!TypeUtil.IsStruct(valueType))
return false;
}


if (valueType.FullName.StartsWith("System.Nullable")) if (valueType.FullName.StartsWith("System.Nullable"))
return false; return false;
Expand Down
4 changes: 4 additions & 0 deletions JSIL/TypeUtil.cs
Expand Up @@ -37,6 +37,10 @@ public static class TypeUtil {
if (git != null) if (git != null)
return git.IsValueType; return git.IsValueType;


var gp = type as GenericParameter;
if (gp != null)
return gp.Constraints.Any((tr) => IsStruct(tr));

return (etype == MetadataType.ValueType); return (etype == MetadataType.ValueType);
} }


Expand Down
3 changes: 2 additions & 1 deletion Tests/ComparisonTests.cs
Expand Up @@ -147,7 +147,8 @@ public class ComparisonTests : GenericTestFixture {
@"TestCases\StructThisAssignment.cs", @"TestCases\StructThisAssignment.cs",
@"TestCases\SingleDimStructArrays.cs", @"TestCases\SingleDimStructArrays.cs",
@"TestCases\MultiDimStructArrays.cs", @"TestCases\MultiDimStructArrays.cs",
@"TestCases\StructLateDeclaration.cs" // This test demonstrates a bug in IntroduceVariableDeclarations @"TestCases\StructLateDeclaration.cs", // This test demonstrates a bug in IntroduceVariableDeclarations
@"TestCases\RefStructThisWithInterface.cs"
}, null, defaultProvider }, null, defaultProvider
); );
} }
Expand Down
39 changes: 39 additions & 0 deletions Tests/TestCases/RefStructThisWithInterface.cs
@@ -0,0 +1,39 @@


using System;

public interface I {
int Value { get; set; }
void Method ();
}

public struct A : I {
public int Value { get; set; }

public void Method () {
Method2(ref this);
I test = this;
test.Value = 12;
Console.WriteLine(this.Value);
}

public void Method2<T> (ref T a) where T : I {
I copy = a;
a.Value += 2;
Console.WriteLine(copy.Value);
}
}

public static class Program {
public static void Test<T> (ref T obj) where T : I {
obj.Value = 4;
obj.Method();
Console.WriteLine(obj.Value);
}

public static void Main (string[] args) {
var obj = new A();
Test(ref obj);
}
}

1 change: 1 addition & 0 deletions Tests/Tests.csproj
Expand Up @@ -176,6 +176,7 @@
<None Include="SpecialTestCases\OverloadedGenericMethodSignatures2.cs" /> <None Include="SpecialTestCases\OverloadedGenericMethodSignatures2.cs" />
<None Include="SpecialTestCases\CustomObjectMethods.cs" /> <None Include="SpecialTestCases\CustomObjectMethods.cs" />
<None Include="SpecialTestCases\CustomEqualsDispatch.cs" /> <None Include="SpecialTestCases\CustomEqualsDispatch.cs" />
<None Include="TestCases\RefStructThisWithInterface.cs" />
<Compile Include="XMLTests.cs" /> <Compile Include="XMLTests.cs" />
<Compile Include="ReflectionTests.cs" /> <Compile Include="ReflectionTests.cs" />
<Compile Include="DependencyTests.cs" /> <Compile Include="DependencyTests.cs" />
Expand Down

0 comments on commit 723cc1d

Please sign in to comment.