Skip to content

Commit

Permalink
TypeVariables know whether or not they are generic type variables upo…
Browse files Browse the repository at this point in the history
…n construction. Scope no longer tracks or cares about whether type variables are generic.
  • Loading branch information
plioi committed Aug 10, 2012
1 parent 59cb304 commit bc56fe6
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 89 deletions.
1 change: 1 addition & 0 deletions src/Rook.Compiling/Rook.Compiling.csproj
Expand Up @@ -91,6 +91,7 @@
<Compile Include="Syntax\RookLexer.cs" />
<Compile Include="Syntax\StringLiteral.cs" />
<Compile Include="Syntax\TypeChecker.cs" />
<Compile Include="Syntax\TypeVariableSource.cs" />
<Compile Include="Syntax\VectorLiteral.cs" />
<Compile Include="Syntax\Binding.cs" />
<Compile Include="Syntax\Block.cs" />
Expand Down
30 changes: 2 additions & 28 deletions src/Rook.Compiling/Scope.cs
Expand Up @@ -10,7 +10,6 @@ public interface Scope
bool TryIncludeUniqueBinding(Binding binding);
bool TryGet(string identifier, out DataType type);
bool Contains(string identifier);
bool IsGeneric(TypeVariable typeVariable);
}

public class GlobalScope : Scope
Expand Down Expand Up @@ -44,8 +43,8 @@ public GlobalScope(TypeChecker typeChecker)
globals["||"] = booleanOperation;
globals["!"] = NamedType.Function(new[] { @bool }, @bool);

var T = typeChecker.CreateTypeVariable(); //TypeVariable 0
var S = typeChecker.CreateTypeVariable(); //TypeVariable 1
var T = typeChecker.CreateGenericTypeVariable(); //TypeVariable 0
var S = typeChecker.CreateGenericTypeVariable(); //TypeVariable 1

globals["??"] = NamedType.Function(new DataType[] { NamedType.Nullable(T), T }, T);
globals["Print"] = NamedType.Function(new[] { T }, NamedType.Void);
Expand Down Expand Up @@ -78,11 +77,6 @@ public bool Contains(string identifier)
{
return globals.Contains(identifier);
}

public bool IsGeneric(TypeVariable typeVariable)
{
return true;
}
}

public sealed class TypeMemberScope : Scope
Expand Down Expand Up @@ -110,11 +104,6 @@ public bool Contains(string identifier)
{
return members.Contains(identifier);
}

public bool IsGeneric(TypeVariable typeVariable)
{
return true;
}
}

public class LocalScope : Scope
Expand Down Expand Up @@ -145,11 +134,6 @@ public bool Contains(string identifier)
{
return locals.Contains(identifier) || parent.Contains(identifier);
}

public bool IsGeneric(TypeVariable typeVariable)
{
return parent.IsGeneric(typeVariable);
}
}

public class LambdaScope : Scope
Expand Down Expand Up @@ -178,15 +162,5 @@ public bool Contains(string identifier)
{
return lambdaBodyScope.Contains(identifier);
}

public bool IsGeneric(TypeVariable typeVariable)
{
return !localNonGenericTypeVariables.Contains(typeVariable) && lambdaBodyScope.IsGeneric(typeVariable);
}

public void TreatAsNonGeneric(IEnumerable<TypeVariable> typeVariables)
{
localNonGenericTypeVariables.AddRange(typeVariables);
}
}
}
34 changes: 20 additions & 14 deletions src/Rook.Compiling/Syntax/TypeChecker.cs
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Parsley;
Expand All @@ -9,7 +8,7 @@ namespace Rook.Compiling.Syntax
{
public class TypeChecker
{
public readonly Func<TypeVariable> CreateTypeVariable;
public readonly TypeVariableSource typeVariables;
private readonly TypeUnifier unifier;
private readonly TypeRegistry typeRegistry;
private readonly List<CompilerError> errorLog;
Expand All @@ -20,8 +19,17 @@ public TypeChecker()
typeRegistry = new TypeRegistry();
errorLog = new List<CompilerError>();

int next = 0;
CreateTypeVariable = () => new TypeVariable(next++);
typeVariables = new TypeVariableSource();
}

public TypeVariable CreateGenericTypeVariable()
{
return typeVariables.CreateGenericTypeVariable();
}

public TypeVariable CreateNonGenericTypeVariable()
{
return typeVariables.CreateNonGenericTypeVariable();
}

public Vector<CompilerError> Errors { get { return errorLog.ToVector(); } }
Expand Down Expand Up @@ -129,18 +137,18 @@ public Expression TypeCheck(Name name, Scope scope)
DataType type;

if (scope.TryGet(Identifier, out type))
return new Name(Position, Identifier, FreshenGenericTypeVariables(scope, type));
return new Name(Position, Identifier, FreshenGenericTypeVariables(type));

LogError(CompilerError.UndefinedIdentifier(name));
return null;
}

private DataType FreshenGenericTypeVariables(Scope scope, DataType type)
private DataType FreshenGenericTypeVariables(DataType type)
{
var substitutions = new Dictionary<TypeVariable, DataType>();
var genericTypeVariables = type.FindTypeVariables().Where(scope.IsGeneric);
var genericTypeVariables = type.FindTypeVariables().Where(x => x.IsGeneric);
foreach (var genericTypeVariable in genericTypeVariables)
substitutions[genericTypeVariable] = CreateTypeVariable();
substitutions[genericTypeVariable] = typeVariables.CreateGenericTypeVariable();

return type.ReplaceTypeVariables(substitutions);
}
Expand Down Expand Up @@ -198,7 +206,7 @@ public Expression TypeCheck(Lambda lambda, Scope scope)

var lambdaScope = new LambdaScope(scope);

var typedParameters = ReplaceImplicitTypesWithNewNonGenericTypeVariables(Parameters, lambdaScope);
var typedParameters = ReplaceImplicitTypesWithNewNonGenericTypeVariables(Parameters);

foreach (var parameter in typedParameters)
{
Expand All @@ -220,7 +228,7 @@ public Expression TypeCheck(Lambda lambda, Scope scope)
return new Lambda(Position, normalizedParameters, typeCheckedBody, NamedType.Function(parameterTypes, typeCheckedBody.Type));
}

private Parameter[] ReplaceImplicitTypesWithNewNonGenericTypeVariables(IEnumerable<Parameter> parameters, LambdaScope lambdaScope)
private Parameter[] ReplaceImplicitTypesWithNewNonGenericTypeVariables(IEnumerable<Parameter> parameters)
{
var decoratedParameters = new List<Parameter>();
var typeVariables = new List<TypeVariable>();
Expand All @@ -229,7 +237,7 @@ private Parameter[] ReplaceImplicitTypesWithNewNonGenericTypeVariables(IEnumerab
{
if (parameter.IsImplicitlyTyped())
{
var typeVariable = CreateTypeVariable();
var typeVariable = this.typeVariables.CreateNonGenericTypeVariable();
typeVariables.Add(typeVariable);
decoratedParameters.Add(new Parameter(parameter.Position, typeVariable, parameter.Identifier));
}
Expand All @@ -239,8 +247,6 @@ private Parameter[] ReplaceImplicitTypesWithNewNonGenericTypeVariables(IEnumerab
}
}

lambdaScope.TreatAsNonGeneric(typeVariables);

return decoratedParameters.ToArray();
}

Expand Down Expand Up @@ -450,7 +456,7 @@ public Expression TypeCheck(Null nullLiteral, Scope scope)
{
var Position = nullLiteral.Position;

return new Null(Position, NamedType.Nullable(CreateTypeVariable()));
return new Null(Position, NamedType.Nullable(typeVariables.CreateGenericTypeVariable()));
}

public Expression TypeCheck(VectorLiteral vectorLiteral, Scope scope)
Expand Down
24 changes: 24 additions & 0 deletions src/Rook.Compiling/Syntax/TypeVariableSource.cs
@@ -0,0 +1,24 @@
using Rook.Compiling.Types;

namespace Rook.Compiling.Syntax
{
public class TypeVariableSource
{
private int next;

public TypeVariableSource()
{
next = 0;
}

public TypeVariable CreateGenericTypeVariable()
{
return new TypeVariable(next++, true);
}

public TypeVariable CreateNonGenericTypeVariable()
{
return new TypeVariable(next++, false);
}
}
}
12 changes: 12 additions & 0 deletions src/Rook.Compiling/Types/TypeVariable.cs
Expand Up @@ -6,17 +6,29 @@ namespace Rook.Compiling.Types
public class TypeVariable : DataType
{
private readonly int name;
private readonly bool isGeneric;

public TypeVariable(int name)
: this(name, true)
{
}

public TypeVariable(int name, bool isGeneric)
{
this.name = name;
this.isGeneric = isGeneric;
}

public override string Name
{
get { return name.ToString(); }
}

public bool IsGeneric
{
get { return isGeneric; }
}

public override IEnumerable<DataType> InnerTypes
{
get { return Enumerable.Empty<DataType>(); }
Expand Down
34 changes: 0 additions & 34 deletions src/Rook.Test/Compiling/ScopeTests.cs
Expand Up @@ -114,40 +114,6 @@ public void DemandsUniqueBindingsWhenIncludingUniqueBindings()
AssertType(Integer, global, "a");
}

[Fact]
public void CanDetermineWhetherAGivenTypeVariableIsGenericWhenPreparedWithAKnownListOfNonGenericTypeVariables()
{
var var0 = new TypeVariable(0);
var var1 = new TypeVariable(1);
var var2 = new TypeVariable(2);
var var3 = new TypeVariable(3);

var outerLambda = new LambdaScope(cd);
var local = new LocalScope(outerLambda);
var middleLambda = new LambdaScope(local);
var local2 = new LocalScope(middleLambda);
var innerLambda = new LambdaScope(local2);

outerLambda.TreatAsNonGeneric(new[] { var0 });
middleLambda.TreatAsNonGeneric(new[] { var1, var2 });
innerLambda.TreatAsNonGeneric(new[] { var3 });

outerLambda.IsGeneric(var0).ShouldBeFalse();
outerLambda.IsGeneric(var1).ShouldBeTrue();
outerLambda.IsGeneric(var2).ShouldBeTrue();
outerLambda.IsGeneric(var3).ShouldBeTrue();

middleLambda.IsGeneric(var0).ShouldBeFalse();
middleLambda.IsGeneric(var1).ShouldBeFalse();
middleLambda.IsGeneric(var2).ShouldBeFalse();
middleLambda.IsGeneric(var3).ShouldBeTrue();

innerLambda.IsGeneric(var0).ShouldBeFalse();
innerLambda.IsGeneric(var1).ShouldBeFalse();
innerLambda.IsGeneric(var2).ShouldBeFalse();
innerLambda.IsGeneric(var3).ShouldBeFalse();
}

private static void AssertType(DataType expectedType, Scope scope, string key)
{
DataType value;
Expand Down
14 changes: 7 additions & 7 deletions src/Rook.Test/Compiling/Syntax/NameTests.cs
Expand Up @@ -33,18 +33,18 @@ public void HasATypeInWhichTypeVariablesAreFreshenedOnEachScopeLookup()
[Fact]
public void HasATypeInWhichOnlyGenericTypeVariablesAreFreshenedOnEachScopeLookup()
{
//Prevents type '1' from being freshened on type lookup by marking it as non-generic in the scope:
//Prevent type '1' from being freshened on type lookup by marking it as non-generic:
var typeVariable1 = new TypeVariable(1, isGeneric: false);

var expectedTypeAfterLookup = new NamedType("A", new TypeVariable(2), new TypeVariable(1), new NamedType("B", new TypeVariable(2), new TypeVariable(1)));
var definedType = new NamedType("A", new TypeVariable(0), new TypeVariable(1), new NamedType("B", new TypeVariable(0), new TypeVariable(1)));
var expectedTypeAfterLookup = new NamedType("A", new TypeVariable(2), typeVariable1, new NamedType("B", new TypeVariable(2), typeVariable1));
var definedType = new NamedType("A", new TypeVariable(0), typeVariable1, new NamedType("B", new TypeVariable(0), typeVariable1));

var typeChecker = new TypeChecker();
var globalScope = new GlobalScope(typeChecker);
var lambdaScope = new LambdaScope(globalScope);
lambdaScope.TreatAsNonGeneric(new[] { new TypeVariable(1) });
lambdaScope.Bind("foo", definedType);
var localScope = new LocalScope(globalScope);
localScope.Bind("foo", definedType);

Type("foo", lambdaScope, typeChecker).ShouldEqual(expectedTypeAfterLookup);
Type("foo", localScope, typeChecker).ShouldEqual(expectedTypeAfterLookup);
}

[Fact]
Expand Down
12 changes: 6 additions & 6 deletions src/Rook.Test/Compiling/Types/TypeCheckerTests.cs
Expand Up @@ -14,9 +14,9 @@ public class TypeCheckerTests
public TypeCheckerTests()
{
typeChecker = new TypeChecker();
x = typeChecker.CreateTypeVariable();
y = typeChecker.CreateTypeVariable();
z = typeChecker.CreateTypeVariable();
x = typeChecker.CreateGenericTypeVariable();
y = typeChecker.CreateGenericTypeVariable();
z = typeChecker.CreateGenericTypeVariable();
}

[Fact]
Expand All @@ -25,9 +25,9 @@ public void ProvidesStreamOfUniqueTypeVariables()
x.ShouldEqual(new TypeVariable(0));
y.ShouldEqual(new TypeVariable(1));
z.ShouldEqual(new TypeVariable(2));
typeChecker.CreateTypeVariable().ShouldEqual(new TypeVariable(3));
typeChecker.CreateTypeVariable().ShouldEqual(new TypeVariable(4));
typeChecker.CreateTypeVariable().ShouldEqual(new TypeVariable(5));
typeChecker.CreateGenericTypeVariable().ShouldEqual(new TypeVariable(3));
typeChecker.CreateNonGenericTypeVariable().ShouldEqual(new TypeVariable(4, false));
typeChecker.CreateGenericTypeVariable().ShouldEqual(new TypeVariable(5));
}
}
}

0 comments on commit bc56fe6

Please sign in to comment.