Skip to content

Commit

Permalink
Unification of higher order polymorphic functions - initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
gcnew committed Dec 16, 2016
1 parent f79fca7 commit 0617c4a
Showing 1 changed file with 39 additions and 3 deletions.
42 changes: 39 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ namespace ts {
return symbol.id;
}

declare let gTypeToString: (type: Type) => string;

export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
// Cancellation that controls whether or not we can cancel in the middle of type checking.
// In general cancelling is *not* safe for the type checker. We might be in the middle of
Expand All @@ -45,6 +47,8 @@ namespace ts {
const Type = objectAllocator.getTypeConstructor();
const Signature = objectAllocator.getSignatureConstructor();

gTypeToString = typeToString;

let typeCount = 0;
let symbolCount = 0;

Expand Down Expand Up @@ -6437,6 +6441,10 @@ namespace ts {
return context.mapper;
}

function identity<T>(x: T): T {
return x;
}

function identityMapper(type: Type): Type {
return type;
}
Expand Down Expand Up @@ -6487,10 +6495,22 @@ namespace ts {
if (signature.typePredicate) {
freshTypePredicate = cloneTypePredicate(signature.typePredicate, mapper);
}
const returnType = instantiateType(signature.resolvedReturnType, mapper);
const callSignature = returnType && getSingleCallSignature(returnType);
if (callSignature && !callSignature.typeParameters && hasFreeTypeVars(callSignature)) {
// this is an inferred signature
const paramTypes = map(callSignature.parameters, getTypeOfSymbol);
if (!contains(paramTypes, callSignature.resolvedReturnType)) {
paramTypes.push(callSignature.resolvedReturnType);
}
const typeParams = <TypeParameter[]>filter(paramTypes, type => !!(type.flags & TypeFlags.TypeParameter));
Debug.assert(!!typeParams.length);
callSignature.typeParameters = typeParams;
}
const result = createSignature(signature.declaration, freshTypeParameters,
signature.thisParameter && instantiateSymbol(signature.thisParameter, mapper),
instantiateList(signature.parameters, mapper, instantiateSymbol),
instantiateType(signature.resolvedReturnType, mapper),
returnType,
freshTypePredicate,
signature.minArgumentCount, signature.hasRestParameter, signature.hasLiteralTypes);
result.target = signature;
Expand Down Expand Up @@ -8750,7 +8770,14 @@ namespace ts {
const targetLen = targetSignatures.length;
const len = sourceLen < targetLen ? sourceLen : targetLen;
for (let i = 0; i < len; i++) {
inferFromSignature(getErasedSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i]));
const sourceSignature = sourceSignatures[sourceLen - len + i];
const targetSignature = targetSignatures[targetLen - len + i];

const mapper = isPolymorphicSignature(sourceSignature) && isPolymorphicSignature(targetSignature)
? identity
: getErasedSignature;

inferFromSignature(mapper(sourceSignature), mapper(targetSignature));
}
}

Expand Down Expand Up @@ -15043,7 +15070,7 @@ namespace ts {
const contextualType = getApparentTypeOfContextualType(<Expression>node);
if (contextualType) {
const contextualSignature = getSingleCallSignature(contextualType);
if (contextualSignature && !contextualSignature.typeParameters) {
if (contextualSignature && !isPolymorphicSignature(contextualSignature)) {
return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper));
}
}
Expand All @@ -15053,6 +15080,15 @@ namespace ts {
return type;
}

function isPolymorphicSignature(signature: Signature | undefined) {
return signature && (signature.typeParameters || hasFreeTypeVars(signature));
}

function hasFreeTypeVars(signature: Signature) {
return signature.resolvedReturnType && signature.resolvedReturnType.flags & TypeFlags.TypeParameter
|| forEach(signature.parameters, (symb) => getTypeOfSymbol(symb).flags & TypeFlags.TypeParameter);
}

// Returns the type of an expression. Unlike checkExpression, this function is simply concerned
// with computing the type and may not fully check all contained sub-expressions for errors.
function getTypeOfExpression(node: Expression) {
Expand Down

0 comments on commit 0617c4a

Please sign in to comment.