use super::*;
use crate::TypeInterner;
#[test]
fn test_callable_same_signature() {
let interner = TypeInterner::new();
let sig = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_method: false,
};
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig.clone()],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, source, target));
}
#[test]
fn test_callable_more_overloads() {
let interner = TypeInterner::new();
let sig1 = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_method: false,
};
let sig2 = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::NUMBER,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::STRING,
type_predicate: None,
is_method: false,
};
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig1.clone(), sig2],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig1],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, source, target));
}
#[test]
fn test_callable_missing_overload() {
let interner = TypeInterner::new();
let sig1 = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_method: false,
};
let sig2 = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::NUMBER,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::STRING,
type_predicate: None,
is_method: false,
};
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig1.clone()],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig1, sig2],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(!is_subtype_of(&interner, source, target));
}
#[test]
fn test_callable_with_construct() {
let interner = TypeInterner::new();
let obj_type = interner.object(vec![PropertyInfo::new(
interner.intern_string("x"),
TypeId::NUMBER,
)]);
let sig = CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: obj_type,
type_predicate: None,
is_method: false,
};
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![],
construct_signatures: vec![sig.clone()],
properties: vec![],
..Default::default()
});
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![],
construct_signatures: vec![sig],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, source, target));
}
#[test]
fn test_callable_covariant_return() {
let interner = TypeInterner::new();
let hello = interner.literal_string("hello");
let source_sig = CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: hello,
type_predicate: None,
is_method: false,
};
let target_sig = CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: TypeId::STRING,
type_predicate: None,
is_method: false,
};
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![source_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![target_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, source, target));
}
#[test]
fn test_function_to_callable() {
let interner = TypeInterner::new();
let fn_type = interner.function(FunctionShape {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_constructor: false,
is_method: false,
});
let callable = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, fn_type, callable));
}
#[test]
fn test_callable_to_function() {
let interner = TypeInterner::new();
let callable = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let fn_type = interner.function(FunctionShape {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_constructor: false,
is_method: false,
});
assert!(is_subtype_of(&interner, callable, fn_type));
}
#[test]
fn test_callable_with_properties() {
let interner = TypeInterner::new();
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![PropertyInfo::new(
interner.intern_string("length"),
TypeId::NUMBER,
)],
..Default::default()
});
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![PropertyInfo::new(
interner.intern_string("length"),
TypeId::NUMBER,
)],
..Default::default()
});
assert!(is_subtype_of(&interner, source, target));
}
#[test]
fn test_callable_missing_property() {
let interner = TypeInterner::new();
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![PropertyInfo::new(
interner.intern_string("length"),
TypeId::NUMBER,
)],
..Default::default()
});
assert!(!is_subtype_of(&interner, source, target));
}
#[test]
fn test_overload_signature_exact_match() {
let interner = TypeInterner::new();
let sig_string_to_number = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_method: false,
};
let sig_number_to_string = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::NUMBER,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::STRING,
type_predicate: None,
is_method: false,
};
let overloaded = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_string_to_number.clone(), sig_number_to_string],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let string_only = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_string_to_number],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, overloaded, string_only));
}
#[test]
fn test_overload_signature_order_priority() {
let interner = TypeInterner::new();
let special_lit = interner.literal_string("special");
let special_return = interner.literal_string("matched-special");
let sig_special = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: special_lit,
optional: false,
rest: false,
}],
this_type: None,
return_type: special_return,
type_predicate: None,
is_method: false,
};
let general_return = interner.literal_string("matched-general");
let sig_general = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: general_return,
type_predicate: None,
is_method: false,
};
let overloaded = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_special.clone(), sig_general],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let specific = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_special],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, overloaded, specific));
}
#[test]
fn test_overload_multiple_arities() {
let interner = TypeInterner::new();
let sig_0 = CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
};
let sig_1 = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_method: false,
};
let sig_2 = CallSignature {
type_params: vec![],
params: vec![
ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
},
ParamInfo {
name: Some(interner.intern_string("y")),
type_id: TypeId::NUMBER,
optional: false,
rest: false,
},
],
this_type: None,
return_type: TypeId::BOOLEAN,
type_predicate: None,
is_method: false,
};
let overloaded = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_0.clone(), sig_1.clone(), sig_2.clone()],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let only_sig0 = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_0],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let only_sig1 = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_1],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let only_sig2 = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_2],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, overloaded, only_sig0));
assert!(is_subtype_of(&interner, overloaded, only_sig1));
assert!(is_subtype_of(&interner, overloaded, only_sig2));
}
#[test]
fn test_generic_overload_simple() {
let interner = TypeInterner::new();
let t_name = interner.intern_string("T");
let t_param = interner.intern(TypeData::TypeParameter(TypeParamInfo {
name: t_name,
constraint: None,
default: None,
is_const: false,
}));
let generic_sig = CallSignature {
type_params: vec![TypeParamInfo {
name: t_name,
constraint: None,
default: None,
is_const: false,
}],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: t_param,
optional: false,
rest: false,
}],
this_type: None,
return_type: t_param,
type_predicate: None,
is_method: false,
};
let generic_fn = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![generic_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let key = interner.lookup(generic_fn).expect("Should have callable");
match key {
TypeData::Callable(shape_id) => {
let shape = interner.callable_shape(shape_id);
assert_eq!(shape.call_signatures.len(), 1);
assert_eq!(shape.call_signatures[0].type_params.len(), 1);
assert_eq!(shape.call_signatures[0].params.len(), 1);
assert_eq!(shape.call_signatures[0].return_type, t_param);
}
_ => panic!("Expected callable type"),
}
}
#[test]
fn test_generic_overload_with_constraint() {
let interner = TypeInterner::new();
let t_name = interner.intern_string("T");
let t_param = interner.intern(TypeData::TypeParameter(TypeParamInfo {
name: t_name,
constraint: Some(TypeId::OBJECT),
default: None,
is_const: false,
}));
let keyof_t = interner.intern(TypeData::KeyOf(t_param));
let constrained_sig = CallSignature {
type_params: vec![TypeParamInfo {
name: t_name,
constraint: Some(TypeId::OBJECT),
default: None,
is_const: false,
}],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: t_param,
optional: false,
rest: false,
}],
this_type: None,
return_type: keyof_t,
type_predicate: None,
is_method: false,
};
let generic_fn = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![constrained_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let key = interner.lookup(generic_fn).expect("Should have callable");
match key {
TypeData::Callable(shape_id) => {
let shape = interner.callable_shape(shape_id);
assert_eq!(shape.call_signatures.len(), 1);
assert!(shape.call_signatures[0].type_params[0].constraint.is_some());
}
_ => panic!("Expected callable type"),
}
}
#[test]
fn test_generic_overload_multiple_type_params() {
let interner = TypeInterner::new();
let t_name = interner.intern_string("T");
let u_name = interner.intern_string("U");
let t_param = interner.intern(TypeData::TypeParameter(TypeParamInfo {
name: t_name,
constraint: None,
default: None,
is_const: false,
}));
let u_param = interner.intern(TypeData::TypeParameter(TypeParamInfo {
name: u_name,
constraint: None,
default: None,
is_const: false,
}));
let tuple_return = interner.tuple(vec![
TupleElement {
type_id: t_param,
name: None,
optional: false,
rest: false,
},
TupleElement {
type_id: u_param,
name: None,
optional: false,
rest: false,
},
]);
let multi_param_sig = CallSignature {
type_params: vec![
TypeParamInfo {
name: t_name,
constraint: None,
default: None,
is_const: false,
},
TypeParamInfo {
name: u_name,
constraint: None,
default: None,
is_const: false,
},
],
params: vec![
ParamInfo {
name: Some(interner.intern_string("x")),
type_id: t_param,
optional: false,
rest: false,
},
ParamInfo {
name: Some(interner.intern_string("y")),
type_id: u_param,
optional: false,
rest: false,
},
],
this_type: None,
return_type: tuple_return,
type_predicate: None,
is_method: false,
};
let generic_fn = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![multi_param_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let key = interner.lookup(generic_fn).expect("Should have callable");
match key {
TypeData::Callable(shape_id) => {
let shape = interner.callable_shape(shape_id);
assert_eq!(shape.call_signatures[0].type_params.len(), 2);
assert_eq!(shape.call_signatures[0].params.len(), 2);
}
_ => panic!("Expected callable type"),
}
}
#[test]
fn test_optional_param_overload_matching() {
let interner = TypeInterner::new();
let sig_required = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::NUMBER,
type_predicate: None,
is_method: false,
};
let sig_optional = CallSignature {
type_params: vec![],
params: vec![
ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
},
ParamInfo {
name: Some(interner.intern_string("y")),
type_id: TypeId::NUMBER,
optional: true,
rest: false,
},
],
this_type: None,
return_type: TypeId::STRING,
type_predicate: None,
is_method: false,
};
let overloaded = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_required.clone(), sig_optional.clone()],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let only_required = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_required],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let only_optional = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![sig_optional],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, overloaded, only_required));
assert!(is_subtype_of(&interner, overloaded, only_optional));
}
#[test]
fn test_all_optional_params_overload() {
let interner = TypeInterner::new();
let all_optional_sig = CallSignature {
type_params: vec![],
params: vec![
ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: true,
rest: false,
},
ParamInfo {
name: Some(interner.intern_string("y")),
type_id: TypeId::NUMBER,
optional: true,
rest: false,
},
],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
};
let fn_with_optional = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![all_optional_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let no_params_sig = CallSignature {
type_params: vec![],
params: vec![],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
};
let no_params = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![no_params_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, no_params, fn_with_optional));
}
#[test]
fn test_optional_and_rest_param_overload() {
let interner = TypeInterner::new();
let number_array = interner.array(TypeId::NUMBER);
let rest_sig = CallSignature {
type_params: vec![],
params: vec![
ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
},
ParamInfo {
name: Some(interner.intern_string("rest")),
type_id: number_array,
optional: false,
rest: true,
},
],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
};
let fn_with_rest = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![rest_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let single_param_sig = CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: TypeId::STRING,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
};
let single_param = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![single_param_sig],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
assert!(is_subtype_of(&interner, single_param, fn_with_rest));
}
#[test]
fn test_contextual_instantiation_generic_call_signature_with_rest_target() {
let interner = TypeInterner::new();
let a_name = interner.intern_string("A");
let b_name = interner.intern_string("B");
let a_param = TypeParamInfo {
name: a_name,
constraint: None,
default: None,
is_const: false,
};
let b_param = TypeParamInfo {
name: b_name,
constraint: None,
default: None,
is_const: false,
};
let a_type = interner.intern(TypeData::TypeParameter(a_param.clone()));
let b_type = interner.intern(TypeData::TypeParameter(b_param.clone()));
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![a_param, b_param],
params: vec![
ParamInfo {
name: Some(interner.intern_string("a")),
type_id: a_type,
optional: true,
rest: false,
},
ParamInfo {
name: Some(interner.intern_string("b")),
type_id: b_type,
optional: true,
rest: false,
},
],
this_type: None,
return_type: b_type,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("s")),
type_id: interner.array(TypeId::STRING),
optional: false,
rest: true,
}],
this_type: None,
return_type: TypeId::STRING,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let mut checker = SubtypeChecker::new(&interner);
checker.strict_function_types = false;
assert!(checker.check_subtype(source, target).is_true());
}
#[test]
fn test_contextual_instantiation_generic_source_ignores_unknown_param_signal() {
let interner = TypeInterner::new();
let t_name = interner.intern_string("T");
let t_param = TypeParamInfo {
name: t_name,
constraint: None,
default: None,
is_const: false,
};
let t_type = interner.intern(TypeData::TypeParameter(t_param.clone()));
let source = interner.function(FunctionShape {
type_params: vec![t_param],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: t_type,
optional: false,
rest: false,
}],
this_type: None,
return_type: t_type,
type_predicate: None,
is_constructor: false,
is_method: false,
});
let placeholder = interner.intern(TypeData::TypeParameter(TypeParamInfo {
name: interner.intern_string("__infer_src_2"),
constraint: None,
default: None,
is_const: false,
}));
let target = interner.function(FunctionShape {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("_")),
type_id: TypeId::UNKNOWN,
optional: false,
rest: false,
}],
this_type: None,
return_type: placeholder,
type_predicate: None,
is_constructor: false,
is_method: false,
});
let mut checker = SubtypeChecker::new(&interner);
checker.strict_function_types = false;
assert!(checker.check_subtype(source, target).is_true());
}
#[test]
#[ignore]
fn test_contextual_instantiation_generic_target_from_source_type_param() {
let interner = TypeInterner::new();
let contextual_t = interner.intern(TypeData::TypeParameter(TypeParamInfo {
name: interner.intern_string("__ctx_t"),
constraint: None,
default: None,
is_const: false,
}));
let source = interner.function(FunctionShape {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("t")),
type_id: contextual_t,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_constructor: false,
is_method: false,
});
let t_name = interner.intern_string("T");
let t_param = TypeParamInfo {
name: t_name,
constraint: None,
default: None,
is_const: false,
};
let t_type = interner.intern(TypeData::TypeParameter(t_param.clone()));
let target = interner.function(FunctionShape {
type_params: vec![t_param],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: t_type,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_constructor: false,
is_method: false,
});
let mut checker = SubtypeChecker::new(&interner);
checker.strict_function_types = true;
assert!(checker.check_subtype(source, target).is_true());
}
#[test]
#[ignore]
fn test_contextual_instantiation_callable_to_generic_function_target() {
let interner = TypeInterner::new();
let contextual_t = interner.intern(TypeData::TypeParameter(TypeParamInfo {
name: interner.intern_string("__ctx_t"),
constraint: None,
default: None,
is_const: false,
}));
let source = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("t")),
type_id: contextual_t,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let t_name = interner.intern_string("T");
let t_param = TypeParamInfo {
name: t_name,
constraint: None,
default: None,
is_const: false,
};
let t_type = interner.intern(TypeData::TypeParameter(t_param.clone()));
let target = interner.function(FunctionShape {
type_params: vec![t_param],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: t_type,
optional: false,
rest: false,
}],
this_type: None,
return_type: TypeId::VOID,
type_predicate: None,
is_constructor: false,
is_method: false,
});
let mut checker = SubtypeChecker::new(&interner);
checker.strict_function_types = true;
assert!(checker.check_subtype(source, target).is_true());
}
#[test]
fn test_contextual_instantiation_generic_function_to_callable_target() {
let interner = TypeInterner::new();
let t_name = interner.intern_string("T");
let t_param = TypeParamInfo {
name: t_name,
constraint: None,
default: None,
is_const: false,
};
let t_type = interner.intern(TypeData::TypeParameter(t_param.clone()));
let source = interner.function(FunctionShape {
type_params: vec![t_param],
params: vec![ParamInfo {
name: Some(interner.intern_string("x")),
type_id: t_type,
optional: false,
rest: false,
}],
this_type: None,
return_type: t_type,
type_predicate: None,
is_constructor: false,
is_method: false,
});
let placeholder = interner.intern(TypeData::TypeParameter(TypeParamInfo {
name: interner.intern_string("__infer_src_3"),
constraint: None,
default: None,
is_const: false,
}));
let target = interner.callable(CallableShape {
symbol: None,
call_signatures: vec![CallSignature {
type_params: vec![],
params: vec![ParamInfo {
name: Some(interner.intern_string("_")),
type_id: TypeId::UNKNOWN,
optional: false,
rest: false,
}],
this_type: None,
return_type: placeholder,
type_predicate: None,
is_method: false,
}],
construct_signatures: vec![],
properties: vec![],
..Default::default()
});
let mut checker = SubtypeChecker::new(&interner);
checker.strict_function_types = false;
assert!(checker.check_subtype(source, target).is_true());
}