Skip to content

Commit

Permalink
Fix for #207
Browse files Browse the repository at this point in the history
  • Loading branch information
kaleidawave committed Nov 12, 2024
1 parent 8530950 commit 6e93bd9
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 116 deletions.
6 changes: 3 additions & 3 deletions checker/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -977,11 +977,11 @@ impl<T: ContextType> Context<T> {
}

pub(crate) fn get_prototype(&self, on: TypeId) -> TypeId {
if let Some(prototype) = self.info.prototypes.get(&on) {
if let Some(prototype) = self.get_chain_of_info().find_map(|info| info.prototypes.get(&on))
{
*prototype
} else if let Some(parent) = self.context_type.get_parent() {
get_on_ctx!(parent.get_prototype(on))
} else {
crate::utilities::notify!("Could not find prototype");
TypeId::OBJECT_TYPE
}
}
Expand Down
16 changes: 10 additions & 6 deletions checker/src/features/constant_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,16 @@ pub(crate) fn call_constant_function(
}
"setPrototypeOf" => {
if let [first, second] = arguments {
let _prototype = environment
.info
.prototypes
.insert(first.non_spread_type().unwrap(), second.non_spread_type().unwrap());
// TODO
Ok(ConstantOutput::Value(TypeId::UNDEFINED_TYPE))
if let (Ok(first), Ok(second)) = (first.non_spread_type(), second.non_spread_type())
{
let _prototype = environment.info.prototypes.insert(first, second);

crate::utilities::notify!("Set {:?} prototype to {:?}", first, second);

Ok(ConstantOutput::Value(first))
} else {
Err(ConstantFunctionError::CannotComputeConstant)
}
} else {
Err(ConstantFunctionError::CannotComputeConstant)
}
Expand Down
101 changes: 53 additions & 48 deletions checker/src/features/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::{
diagnostics::TypeStringRepresentation,
events::RootReference,
types::{
get_constraint,
get_constraint, helpers,
logical::{Logical, LogicalOrValid},
properties, PartiallyAppliedGenerics, TypeStore,
},
Expand Down Expand Up @@ -431,58 +431,63 @@ pub(crate) fn has_property(
information: &impl InformationChain,
types: &mut TypeStore,
) -> TypeId {
match types.get_type_by_id(rhs) {
Type::Interface { .. }
| Type::Class { .. }
| Type::Constant(_)
| Type::FunctionReference(_)
| Type::Object(_)
| Type::PartiallyAppliedGenerics(_)
| Type::And(_, _)
| Type::SpecialObject(_)
| Type::Narrowed { .. }
| Type::AliasTo { .. } => {
let result = properties::get_property_unbound(
(rhs, None),
(publicity, key, None),
false,
information,
types,
);
match result {
Ok(LogicalOrValid::Logical(result)) => match result {
Logical::Pure(_) => TypeId::TRUE,
Logical::Or { .. } => {
crate::utilities::notify!("or or implies `in`");
TypeId::UNIMPLEMENTED_ERROR_TYPE
}
Logical::Implies { .. } => {
crate::utilities::notify!("or or implies `in`");
if let Some((condition, truthy, falsy)) = helpers::get_type_as_conditional(rhs, types) {
let truthy_result = has_property((publicity, key), truthy, information, types);
let otherwise_result = has_property((publicity, key), falsy, information, types);
types.new_conditional_type(condition, truthy_result, otherwise_result)
} else {
match types.get_type_by_id(rhs) {
Type::Interface { .. }
| Type::Class { .. }
| Type::Constant(_)
| Type::FunctionReference(_)
| Type::Object(_)
| Type::PartiallyAppliedGenerics(_)
| Type::And(_, _)
| Type::SpecialObject(_)
| Type::Narrowed { .. }
| Type::AliasTo { .. } => {
let result = properties::get_property_unbound(
(rhs, None),
(publicity, key, None),
false,
information,
types,
);
match result {
Ok(LogicalOrValid::Logical(result)) => match result {
Logical::Pure(_) => TypeId::TRUE,
Logical::Or { .. } => {
crate::utilities::notify!("or or implies `in`");
TypeId::UNIMPLEMENTED_ERROR_TYPE
}
Logical::Implies { .. } => {
crate::utilities::notify!("or or implies `in`");
TypeId::UNIMPLEMENTED_ERROR_TYPE
}
Logical::BasedOnKey { .. } => {
crate::utilities::notify!("mapped in");
TypeId::UNIMPLEMENTED_ERROR_TYPE
}
},
Ok(LogicalOrValid::NeedsCalculation(result)) => {
crate::utilities::notify!("TODO {:?}", result);
TypeId::UNIMPLEMENTED_ERROR_TYPE
}
Logical::BasedOnKey { .. } => {
crate::utilities::notify!("mapped in");
TypeId::UNIMPLEMENTED_ERROR_TYPE
Err(err) => {
crate::utilities::notify!("TODO {:?}", err);
TypeId::FALSE
}
},
Ok(LogicalOrValid::NeedsCalculation(result)) => {
crate::utilities::notify!("TODO {:?}", result);
TypeId::UNIMPLEMENTED_ERROR_TYPE
}
Err(err) => {
crate::utilities::notify!("TODO {:?}", err);
TypeId::FALSE
}
}
}
Type::Or(_, _) => {
crate::utilities::notify!("Condtionally");
TypeId::UNIMPLEMENTED_ERROR_TYPE
}
Type::RootPolyType(_) | Type::Constructor(_) => {
crate::utilities::notify!("Queue event / create dependent");
let constraint = get_constraint(rhs, types).unwrap();
has_property((publicity, key), constraint, information, types)
Type::Or(_, _) => {
unreachable!()
}
Type::RootPolyType(_) | Type::Constructor(_) => {
crate::utilities::notify!("Queue event / create dependent");
let constraint = get_constraint(rhs, types).unwrap();
has_property((publicity, key), constraint, information, types)
}
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion checker/src/types/calling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,10 @@ fn call_logical<B: CallCheckingBehavior>(
|| is_independent_function
|| matches!(
const_fn_ident.as_str(),
"satisfies" | "is_dependent" | "bind" | "proxy:constructor"
"satisfies"
| "is_dependent" | "bind"
| "proxy:constructor" | "setPrototypeOf"
| "getPrototypeOf"
);

// {
Expand Down
45 changes: 32 additions & 13 deletions checker/src/types/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ pub fn _type_is_error(ty: TypeId, types: &TypeStore) -> bool {

/// TODO want to skip mapped generics because that would break subtyping
#[must_use]
pub fn get_conditional(ty: TypeId, types: &TypeStore) -> Option<(TypeId, TypeId, TypeId)> {
pub fn get_type_as_conditional(ty: TypeId, types: &TypeStore) -> Option<(TypeId, TypeId, TypeId)> {
match types.get_type_by_id(ty) {
Type::Constructor(crate::types::Constructor::ConditionalResult {
condition,
Expand All @@ -226,7 +226,7 @@ pub fn get_conditional(ty: TypeId, types: &TypeStore) -> Option<(TypeId, TypeId,
Type::RootPolyType(PolyNature::MappedGeneric { .. }) => None,
_ => {
if let Some(constraint) = get_constraint(ty, types) {
get_conditional(constraint, types)
get_type_as_conditional(constraint, types)
} else {
None
}
Expand Down Expand Up @@ -324,28 +324,47 @@ pub struct AndCondition(pub TypeId);
#[derive(Debug)]
pub struct OrCase(pub Vec<AndCondition>);

pub fn into_conditions(ty: TypeId, types: &TypeStore) -> Vec<AndCondition> {
// TODO aliases and such
if let Type::And(lhs, rhs) = types.get_type_by_id(ty) {
pub fn into_conditions(id: TypeId, types: &TypeStore) -> Vec<AndCondition> {
let ty = types.get_type_by_id(id);
if let Type::And(lhs, rhs) = ty {
let mut buf = into_conditions(*lhs, types);
buf.append(&mut into_conditions(*rhs, types));
buf
} else if let Some(backing) = get_constraint_or_alias(ty, types) {
into_conditions(backing, types)
} else if let Type::RootPolyType(rpt) = ty {
into_conditions(rpt.get_constraint(), types)
} else if let Type::Narrowed { narrowed_to, .. } = ty {
into_conditions(*narrowed_to, types)
} else {
vec![AndCondition(ty)]
// Temp fix
if let Type::Constructor(Constructor::BinaryOperator { result, .. }) = ty {
if !matches!(*result, TypeId::NUMBER_TYPE | TypeId::STRING_TYPE) {
return into_conditions(*result, types);
}
}

vec![AndCondition(id)]
}

// else if let Some(backing) = get_constraint_or_alias(ty, types) {
// // TODO temp to keep information
// let mut buf = vec![ty];
// buf.append(&mut into_conditions(*backing, types));
// buf
// }
}

pub fn into_cases(ty: TypeId, types: &TypeStore) -> Vec<OrCase> {
if let Type::Or(lhs, rhs) = types.get_type_by_id(ty) {
pub fn into_cases(id: TypeId, types: &TypeStore) -> Vec<OrCase> {
let ty = types.get_type_by_id(id);
if let Type::Or(lhs, rhs) = ty {
let mut buf = into_cases(*lhs, types);
buf.append(&mut into_cases(*rhs, types));
buf
} else if let Some(backing) = get_constraint_or_alias(ty, types) {
into_cases(backing, types)
} else if let Type::RootPolyType(rpt) = ty {
into_cases(rpt.get_constraint(), types)
} else if let Type::Narrowed { narrowed_to, .. } = ty {
into_cases(*narrowed_to, types)
} else {
vec![OrCase(into_conditions(ty, types))]
vec![OrCase(into_conditions(id, types))]
}
}

Expand Down
6 changes: 0 additions & 6 deletions checker/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,9 +763,3 @@ impl TypeCombinable for TypeId {
TypeId::UNDEFINED_TYPE
}
}

/// Used for **both** inference and narrowing
pub enum Confirmation {
HasProperty { on: (), property: () },
IsType { on: (), ty: () },
}
82 changes: 43 additions & 39 deletions checker/src/types/properties/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
contributions::CovariantContribution, generic_type_arguments::GenericArguments,
},
get_constraint,
helpers::{get_conditional, is_inferrable_type, is_pseudo_continous},
helpers::{get_type_as_conditional, is_inferrable_type, is_pseudo_continous},
logical::{
BasedOnKey, Invalid, Logical, LogicalOrValid, NeedsCalculation, PossibleLogical,
PropertyOn,
Expand Down Expand Up @@ -335,8 +335,11 @@ pub(crate) fn get_property_unbound(
}
Type::Constructor(crate::types::Constructor::ConditionalResult { .. })
| Type::Or(..) => {
crate::utilities::notify!("Here {:?}", on);

let (condition, truthy_result, otherwise_result) =
get_conditional(on, types).expect("case above != get_conditional");
get_type_as_conditional(on, types)
.expect("case above != get_type_as_conditional");

if require_both_logical {
let left = get_property_on_type_unbound(
Expand Down Expand Up @@ -372,14 +375,16 @@ pub(crate) fn get_property_unbound(
types,
);
if left.is_err() && right.is_err() {
crate::utilities::notify!(
"One side invalid {:?}",
(left.is_err(), right.is_err())
);
Err(Invalid(on))
} else {
let left = left.unwrap_or(LogicalOrValid::Logical(Logical::Pure(
PropertyValue::Deleted,
)));
let right = right.unwrap_or(LogicalOrValid::Logical(Logical::Pure(
PropertyValue::Deleted,
)));
const DELETED_PROPERTY: LogicalOrValid<PropertyValue> =
LogicalOrValid::Logical(Logical::Pure(PropertyValue::Deleted));
let left = left.unwrap_or(DELETED_PROPERTY);
let right = right.unwrap_or(DELETED_PROPERTY);
Ok(Logical::Or { condition, left: Box::new(left), right: Box::new(right) }
.into())
}
Expand Down Expand Up @@ -430,49 +435,46 @@ pub(crate) fn get_property_unbound(
.find_map(|facts| facts.prototypes.get(&on))
.copied();

let generics = if let Some(generics) = object_constraint_structure_generics {
// TODO clone
Some(generics.clone())
} else if prototype
.is_some_and(|prototype| types.lookup_generic_map.contains_key(&prototype))
{
Some(GenericArguments::LookUp { on })
} else {
None
};

let on_self = resolver(
(on, on_type_arguments),
(publicity, under, under_type_arguments),
info_chain,
types,
);

let result = if let (Some(prototype), None) = (prototype, &on_self) {
resolver(
if let Some(property) = on_self {
let generics = if let Some(generics) = object_constraint_structure_generics {
// TODO clone
Some(generics.clone())
} else if prototype
.is_some_and(|prototype| types.lookup_generic_map.contains_key(&prototype))
{
Some(GenericArguments::LookUp { on })
} else {
None
};

let property = wrap(property);
let property = if let Some(ref generics) = generics {
// TODO clone
Logical::Implies { on: Box::new(property), antecedent: generics.clone() }
} else {
property
};
Ok(LogicalOrValid::Logical(property))
} else if let Some(prototype) = prototype {
crate::utilities::notify!("{:?}", types.get_type_by_id(prototype));

get_property_on_type_unbound(
(prototype, on_type_arguments),
(publicity, under, under_type_arguments),
require_both_logical,
info_chain,
types,
)
} else {
on_self
};

// crate::utilities::notify!("result={:?}", result);

result
.map(wrap)
.map(|result| {
if let Some(ref generics) = generics {
// TODO clone
Logical::Implies { on: Box::new(result), antecedent: generics.clone() }
} else {
result
}
})
.map(LogicalOrValid::Logical)
.ok_or(Invalid(on))
Err(Invalid(on))
}
}
Type::Interface { extends, .. } => resolver(
(on, on_type_arguments),
Expand Down Expand Up @@ -602,7 +604,9 @@ pub(crate) fn get_property_unbound(
// if *key == TypeId::ERROR_TYPE {
// return Err(MissingOrToCalculate::Error);
// } else
if let Some((condition, truthy_result, otherwise_result)) = get_conditional(key, types) {
if let Some((condition, truthy_result, otherwise_result)) =
get_type_as_conditional(key, types)
{
let left = get_property_unbound(
(on, on_type_arguments),
(publicity, &PropertyKey::Type(truthy_result), under_type_arguments),
Expand Down

0 comments on commit 6e93bd9

Please sign in to comment.