Skip to content

Commit

Permalink
Fix for gajus#237 with test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
vlsergey committed Jun 22, 2020
1 parent 864fe15 commit fa6856a
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* @flow */

import type TypeContext from '../../../TypeContext';

function defineClass(t: TypeContext) {
let _t$TypeParametersSymb;
var _dec, _class, _class2, _temp;
const _TestClassTypeParametersSymbol = Symbol("TestClassTypeParameters");

let TestClass = (_dec = t.annotate(t.class("TestClass", TestClass => {
const ValueType = TestClass.typeParameter("ValueType");
return [t.method("testMethod")];
})), _dec(_class = (_temp = (_t$TypeParametersSymb = t.TypeParametersSymbol, _class2 = class TestClass {
constructor() {
this[_TestClassTypeParametersSymbol] = {
ValueType: t.typeParameter("ValueType")
};
}

testMethod() {
const items = t.array(this[_TestClassTypeParametersSymbol].ValueType)
.assert(JSON.parse('[{ "a": null, "b": "b" }, { "a": "a", "b": null }]'));
return items;
}

}), _class2[_t$TypeParametersSymb] = _TestClassTypeParametersSymbol, _temp)) || _class);
return TestClass;
}

// will work for const test = TestClass<any>();
export function pass(t: TypeContext) {
const TestClass = defineClass(t);
const testClass = t.ref(TestClass, t.any()).assert(new TestClass());
return testClass.testMethod();
}

// will fail for const test = TestClass();
export function fail(t: TypeContext) {
const TestClass = defineClass(t);
const testClass = t.ref(TestClass).assert(new TestClass());
return testClass.testMethod();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* @flow */

import type TypeContext from '../../../TypeContext';

function defineClass(t: TypeContext) {
let _t$TypeParametersSymb;
var _dec, _class, _class2, _temp;
const _TestClassTypeParametersSymbol = Symbol("TestClassTypeParameters");

let TestClass = (_dec = t.annotate(t.class("TestClass", TestClass => {
const Value1Type = TestClass.typeParameter("ValueType1");
const Value2Type = TestClass.typeParameter("ValueType2");
return [t.method("testMethod")];
})), _dec(_class = (_temp = (_t$TypeParametersSymb = t.TypeParametersSymbol, _class2 = class TestClass {
constructor() {
this[_TestClassTypeParametersSymbol] = {
ValueType1: t.typeParameter("ValueType1"),
ValueType2: t.typeParameter("ValueType2")
};
}

testMethod() {
const items1 = t.array(this[_TestClassTypeParametersSymbol].ValueType1)
.assert(JSON.parse('[{ "a": null, "b": "b" }, { "a": "a", "b": null }]'));
const items2 = t.array(this[_TestClassTypeParametersSymbol].ValueType2)
.assert(JSON.parse('[{ "a": null, "b": "b" }, { "a": "a", "b": null }]'));
return items1.concat(items2);
}

}), _class2[_t$TypeParametersSymb] = _TestClassTypeParametersSymbol, _temp)) || _class);
return TestClass;
}

// will work for const test = TestClass<any, any>();
export function pass(t: TypeContext) {
const TestClass = defineClass(t);
const testClass = t.ref(TestClass, t.any(), t.any()).assert(new TestClass());
return testClass.testMethod();
}

// will fail for const test = TestClass();
export function fail(t: TypeContext) {
const TestClass = defineClass(t);
const testClass = t.ref(TestClass).assert(new TestClass());
return testClass.testMethod();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* @flow */

import type TypeContext from '../../../TypeContext';

function defineClass(t: TypeContext) {
let _t$TypeParametersSymb;
var _dec, _class, _class2, _temp;
const _TestClassTypeParametersSymbol = Symbol("TestClassTypeParameters");

let TestClass = (_dec = t.annotate(t.class("TestClass", TestClass => {
const ValueType = TestClass.typeParameter("ValueType");
return [t.method("testMethod")];
})), _dec(_class = (_temp = (_t$TypeParametersSymb = t.TypeParametersSymbol, _class2 = class TestClass {
constructor() {
this[_TestClassTypeParametersSymbol] = {
ValueType: t.typeParameter("ValueType"),
};
}

testMethod( toParse ) {
return t.array(this[_TestClassTypeParametersSymbol].ValueType).assert(JSON.parse(toParse));
}

}), _class2[_t$TypeParametersSymb] = _TestClassTypeParametersSymbol, _temp)) || _class);
return TestClass;
}

export function pass(t: TypeContext) {
const TestClass = defineClass(t);

t.ref(TestClass, t.string()).assert(new TestClass()).testMethod('["string1", "string2"]');
t.ref(TestClass, t.number()).assert(new TestClass()).testMethod('[0, 1, 2, 3]');
t.ref(TestClass, t.boolean()).assert(new TestClass()).testMethod('[false, true]');
return true;
}

// internal type still used for type validation inside testMethod()
export function fail(t: TypeContext) {
const TestClass = defineClass(t);
t.ref(TestClass, t.number()).assert(new TestClass())
.testMethod('["string1", "string2"]');
}
27 changes: 27 additions & 0 deletions packages/flow-runtime/src/types/TypeParameterApplication.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import type {ApplicableType} from './';

import type ObjectTypeProperty from './ObjectTypeProperty';

import ParameterizedClassDeclaration from "../declarations/ParameterizedClassDeclaration";

import {TypeParametersSymbol, TypeSymbol} from "../symbols";

/**
* # TypeParameterApplication
*
Expand All @@ -19,6 +23,29 @@ export default class TypeParameterApplication<X, T> extends Type {

*errors (validation: Validation<any>, path: IdentifierPath, input: any): Generator<ErrorTuple, void, void> {
const {parent, typeInstances} = this;

// explicitly set recorded type parameter in TypeParameter
if (parent && parent.impl && parent.impl[TypeSymbol] && input) {
const parentType : Type = parent.impl[TypeSymbol];

if (parentType instanceof ParameterizedClassDeclaration) {
const declTypeParameters = parentType.typeParameters;
const parentTypeParameters : Symbol = parent.impl[TypeParametersSymbol];
const inputTypeParameters = input[parentTypeParameters];

if (declTypeParameters && inputTypeParameters
&& declTypeParameters.length !== 0
&& declTypeParameters.length === this.typeInstances.length) {
declTypeParameters.forEach( (declTypeParameter : TypeParameter, index : number) => {
const inputTypeParameter : TypeParameter = inputTypeParameters[declTypeParameter.id];
if (inputTypeParameter) {
inputTypeParameter.recorded = this.typeInstances[index];
}
} );
}
}
}

yield* parent.errors(validation, path, input, ...typeInstances);
}

Expand Down

0 comments on commit fa6856a

Please sign in to comment.