From 6e93bd9558693cb2f4597236b370a21cdd08a27e Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 12 Nov 2024 19:30:04 +0000 Subject: [PATCH] Fix for #207 --- checker/src/context/mod.rs | 6 +- checker/src/features/constant_functions.rs | 16 ++-- checker/src/features/mod.rs | 101 +++++++++++---------- checker/src/types/calling.rs | 5 +- checker/src/types/helpers.rs | 45 ++++++--- checker/src/types/mod.rs | 6 -- checker/src/types/properties/access.rs | 82 +++++++++-------- 7 files changed, 145 insertions(+), 116 deletions(-) diff --git a/checker/src/context/mod.rs b/checker/src/context/mod.rs index 368de944..e39c2482 100644 --- a/checker/src/context/mod.rs +++ b/checker/src/context/mod.rs @@ -977,11 +977,11 @@ impl Context { } 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 } } diff --git a/checker/src/features/constant_functions.rs b/checker/src/features/constant_functions.rs index ee09d9ce..9c359f1b 100644 --- a/checker/src/features/constant_functions.rs +++ b/checker/src/features/constant_functions.rs @@ -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) } diff --git a/checker/src/features/mod.rs b/checker/src/features/mod.rs index b69a2464..a00d20e1 100644 --- a/checker/src/features/mod.rs +++ b/checker/src/features/mod.rs @@ -28,7 +28,7 @@ use crate::{ diagnostics::TypeStringRepresentation, events::RootReference, types::{ - get_constraint, + get_constraint, helpers, logical::{Logical, LogicalOrValid}, properties, PartiallyAppliedGenerics, TypeStore, }, @@ -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) + } } } } diff --git a/checker/src/types/calling.rs b/checker/src/types/calling.rs index 09210f99..9ea6c083 100644 --- a/checker/src/types/calling.rs +++ b/checker/src/types/calling.rs @@ -614,7 +614,10 @@ fn call_logical( || is_independent_function || matches!( const_fn_ident.as_str(), - "satisfies" | "is_dependent" | "bind" | "proxy:constructor" + "satisfies" + | "is_dependent" | "bind" + | "proxy:constructor" | "setPrototypeOf" + | "getPrototypeOf" ); // { diff --git a/checker/src/types/helpers.rs b/checker/src/types/helpers.rs index f0c50040..27fa2038 100644 --- a/checker/src/types/helpers.rs +++ b/checker/src/types/helpers.rs @@ -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, @@ -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 } @@ -324,28 +324,47 @@ pub struct AndCondition(pub TypeId); #[derive(Debug)] pub struct OrCase(pub Vec); -pub fn into_conditions(ty: TypeId, types: &TypeStore) -> Vec { - // 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 { + 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 { - if let Type::Or(lhs, rhs) = types.get_type_by_id(ty) { +pub fn into_cases(id: TypeId, types: &TypeStore) -> Vec { + 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))] } } diff --git a/checker/src/types/mod.rs b/checker/src/types/mod.rs index e8e4ae5d..ce22d99c 100644 --- a/checker/src/types/mod.rs +++ b/checker/src/types/mod.rs @@ -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: () }, -} diff --git a/checker/src/types/properties/access.rs b/checker/src/types/properties/access.rs index 753333f9..405e6efe 100644 --- a/checker/src/types/properties/access.rs +++ b/checker/src/types/properties/access.rs @@ -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, @@ -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( @@ -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 = + 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()) } @@ -430,17 +435,6 @@ 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), @@ -448,31 +442,39 @@ pub(crate) fn get_property_unbound( 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), @@ -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),