diff --git a/api/sixtyfps-node/native/js_model.rs b/api/sixtyfps-node/native/js_model.rs index deb38541a..dd121b744 100644 --- a/api/sixtyfps-node/native/js_model.rs +++ b/api/sixtyfps-node/native/js_model.rs @@ -9,7 +9,7 @@ LICENSE END */ use neon::prelude::*; -use sixtyfps_compilerlib::typeregister::Type; +use sixtyfps_compilerlib::langtype::Type; use sixtyfps_corelib::model::Model; use std::cell::Cell; use std::rc::{Rc, Weak}; diff --git a/api/sixtyfps-node/native/lib.rs b/api/sixtyfps-node/native/lib.rs index c4f5d1abf..ead4f5ccb 100644 --- a/api/sixtyfps-node/native/lib.rs +++ b/api/sixtyfps-node/native/lib.rs @@ -9,7 +9,7 @@ LICENSE END */ use core::cell::RefCell; use neon::prelude::*; -use sixtyfps_compilerlib::typeregister::Type; +use sixtyfps_compilerlib::langtype::Type; use sixtyfps_corelib::Resource; use std::rc::Rc; @@ -150,7 +150,7 @@ fn create<'cx>( fn to_eval_value<'cx>( val: Handle<'cx, JsValue>, - ty: sixtyfps_compilerlib::typeregister::Type, + ty: sixtyfps_compilerlib::langtype::Type, cx: &mut impl Context<'cx>, persistent_context: &persistent_context::PersistentContext<'cx>, ) -> NeonResult { diff --git a/sixtyfps_compiler/expression_tree.rs b/sixtyfps_compiler/expression_tree.rs index 2b9c0ece3..4be881be0 100644 --- a/sixtyfps_compiler/expression_tree.rs +++ b/sixtyfps_compiler/expression_tree.rs @@ -8,9 +8,9 @@ Please contact info@sixtyfps.io for more information. LICENSE END */ use crate::diagnostics::{BuildDiagnostics, Spanned, SpannedWithSourceFile}; +use crate::langtype::{BuiltinElement, EnumerationValue, Type}; use crate::object_tree::*; use crate::parser::SyntaxNodeWithSourceFile; -use crate::typeregister::{BuiltinElement, EnumerationValue, Type}; use core::cell::RefCell; use std::collections::HashMap; use std::hash::Hash; diff --git a/sixtyfps_compiler/generator.rs b/sixtyfps_compiler/generator.rs index 5c3f26977..126d66bb1 100644 --- a/sixtyfps_compiler/generator.rs +++ b/sixtyfps_compiler/generator.rs @@ -133,7 +133,7 @@ pub fn build_array_helper( pub fn is_flickable(e: &ElementRc) -> bool { match &e.borrow().base_type { - crate::typeregister::Type::Native(n) if n.class_name == "Flickable" => true, + crate::langtype::Type::Native(n) if n.class_name == "Flickable" => true, _ => false, } } diff --git a/sixtyfps_compiler/generator/cpp.rs b/sixtyfps_compiler/generator/cpp.rs index 6c6e36509..eaa636917 100644 --- a/sixtyfps_compiler/generator/cpp.rs +++ b/sixtyfps_compiler/generator/cpp.rs @@ -186,9 +186,9 @@ use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, Level, Spanned}; use crate::expression_tree::{ BuiltinFunction, EasingCurve, Expression, ExpressionSpanned, NamedReference, }; +use crate::langtype::Type; use crate::layout::{gen::LayoutItemCodeGen, Layout, LayoutElement, LayoutGeometry}; use crate::object_tree::{Component, Document, Element, ElementRc, RepeatedElementInfo}; -use crate::typeregister::Type; use cpp_ast::*; use itertools::Itertools; use std::collections::HashMap; diff --git a/sixtyfps_compiler/generator/rust.rs b/sixtyfps_compiler/generator/rust.rs index 11ae176ee..31492906e 100644 --- a/sixtyfps_compiler/generator/rust.rs +++ b/sixtyfps_compiler/generator/rust.rs @@ -14,9 +14,9 @@ use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, Level, Spanned}; use crate::expression_tree::{ BuiltinFunction, EasingCurve, Expression, NamedReference, OperatorClass, Path, }; +use crate::langtype::Type; use crate::layout::{gen::LayoutItemCodeGen, Layout, LayoutElement, LayoutGeometry}; use crate::object_tree::{Component, Document, ElementRc}; -use crate::typeregister::Type; use proc_macro2::TokenStream; use quote::{format_ident, quote}; use std::rc::Rc; diff --git a/sixtyfps_compiler/langtype.rs b/sixtyfps_compiler/langtype.rs new file mode 100644 index 000000000..6daf090a8 --- /dev/null +++ b/sixtyfps_compiler/langtype.rs @@ -0,0 +1,578 @@ +/* LICENSE BEGIN + This file is part of the SixtyFPS Project -- https://sixtyfps.io + Copyright (c) 2020 Olivier Goffart + Copyright (c) 2020 Simon Hausmann + + SPDX-License-Identifier: GPL-3.0-only + This file is also available under commercial licensing terms. + Please contact info@sixtyfps.io for more information. +LICENSE END */ +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::{fmt::Display, rc::Rc}; + +use crate::expression_tree::{Expression, Unit}; +use crate::object_tree::Component; +use crate::typeregister::TypeRegister; + +#[derive(Debug, Clone)] +pub enum Type { + /// Correspond to an uninitialized type, or an error + Invalid, + /// The type of an expression that return nothing + Void, + Component(Rc), + Builtin(Rc), + Native(Rc), + + Signal { + args: Vec, + }, + Function { + return_type: Box, + args: Vec, + }, + + // Other property types: + Float32, + Int32, + String, + Color, + Duration, + Length, + LogicalLength, + Percent, + Resource, + Bool, + Model, + PathElements, + Easing, + + Array(Box), + Object(BTreeMap), + + Enumeration(Rc), + EnumerationValue(EnumerationValue), + + ElementReference, +} + +impl core::cmp::PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + match self { + Type::Invalid => matches!(other, Type::Invalid), + Type::Void => matches!(other, Type::Void), + Type::Component(a) => matches!(other, Type::Component(b) if Rc::ptr_eq(a, b)), + Type::Builtin(a) => matches!(other, Type::Builtin(b) if Rc::ptr_eq(a, b)), + Type::Native(a) => matches!(other, Type::Native(b) if Rc::ptr_eq(a, b)), + Type::Signal { args: a } => matches!(other, Type::Signal { args: b } if a == b), + Type::Function { return_type: lhs_rt, args: lhs_args } => { + matches!(other, Type::Function { return_type: rhs_rt, args: rhs_args } if lhs_rt == rhs_rt && lhs_args == rhs_args) + } + Type::Float32 => matches!(other, Type::Float32), + Type::Int32 => matches!(other, Type::Int32), + Type::String => matches!(other, Type::String), + Type::Color => matches!(other, Type::Color), + Type::Duration => matches!(other, Type::Duration), + Type::Length => matches!(other, Type::Length), + Type::LogicalLength => matches!(other, Type::LogicalLength), + Type::Percent => matches!(other, Type::Percent), + Type::Resource => matches!(other, Type::Resource), + Type::Bool => matches!(other, Type::Bool), + Type::Model => matches!(other, Type::Model), + Type::PathElements => matches!(other, Type::PathElements), + Type::Easing => matches!(other, Type::Easing), + Type::Array(a) => matches!(other, Type::Array(b) if a == b), + Type::Object(a) => matches!(other, Type::Object(b) if a == b), + Type::Enumeration(lhs) => matches!(other, Type::Enumeration(rhs) if lhs == rhs), + Type::EnumerationValue(lhs) => { + matches!(other, Type::EnumerationValue(rhs) if lhs == rhs) + } + Type::ElementReference => matches!(other, Type::ElementReference), + } + } +} + +impl Display for Type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Type::Invalid => write!(f, ""), + Type::Void => write!(f, "void"), + Type::Component(c) => c.id.fmt(f), + Type::Builtin(b) => b.native_class.class_name.fmt(f), + Type::Native(b) => b.class_name.fmt(f), + Type::Signal { args } => { + write!(f, "signal")?; + if !args.is_empty() { + write!(f, "(")?; + for (i, arg) in args.iter().enumerate() { + if i > 0 { + write!(f, ",")?; + } + write!(f, "{}", arg)?; + } + write!(f, ")")? + } + Ok(()) + } + Type::Function { return_type, args } => { + write!(f, "function(")?; + for (i, arg) in args.iter().enumerate() { + if i > 0 { + write!(f, ",")?; + } + write!(f, "{}", arg)?; + } + write!(f, ") -> {}", return_type) + } + Type::Float32 => write!(f, "float"), + Type::Int32 => write!(f, "int"), + Type::String => write!(f, "string"), + Type::Duration => write!(f, "duration"), + Type::Length => write!(f, "length"), + Type::LogicalLength => write!(f, "logical_length"), + Type::Percent => write!(f, "percent"), + Type::Color => write!(f, "color"), + Type::Resource => write!(f, "resource"), + Type::Bool => write!(f, "bool"), + Type::Model => write!(f, "model"), + Type::Array(t) => write!(f, "[{}]", t), + Type::Object(t) => { + write!(f, "{{ ")?; + for (k, v) in t { + write!(f, "{}: {},", k, v)?; + } + write!(f, "}}") + } + Type::PathElements => write!(f, "pathelements"), + Type::Easing => write!(f, "easing"), + Type::Enumeration(enumeration) => write!(f, "enum {}", enumeration.name), + Type::EnumerationValue(value) => { + write!(f, "enum {}::{}", value.enumeration.name, value.to_string()) + } + Type::ElementReference => write!(f, "element ref"), + } + } +} + +impl Type { + pub fn is_object_type(&self) -> bool { + matches!(self, Self::Component(_) | Self::Builtin(_)) + } + + /// valid type for properties + pub fn is_property_type(&self) -> bool { + match self { + Self::Float32 + | Self::Int32 + | Self::String + | Self::Color + | Self::Duration + | Self::Length + | Self::LogicalLength + | Self::Percent + | Self::Resource + | Self::Bool + | Self::Model + | Self::Easing + | Self::Enumeration(_) + | Self::ElementReference + | Self::Object(_) + | Self::Array(_) => true, + Self::Component(c) => c.root_element.borrow().base_type == Type::Void, + _ => false, + } + } + + pub fn ok_for_public_api(&self) -> bool { + // Duration and Easing don't have good types for public API exposure yet. + !matches!(self, Self::Duration | Self::Easing) + } + + pub fn lookup_property(&self, name: &str) -> Type { + match self { + Type::Component(c) => c.root_element.borrow().lookup_property(name), + Type::Builtin(b) => b.properties.get(name).cloned().unwrap_or_else(|| { + if b.is_non_item_type { + Type::Invalid + } else { + crate::typeregister::reserved_property(name) + } + }), + Type::Native(n) => n.lookup_property(name).unwrap_or_default(), + _ => Type::Invalid, + } + } + + pub fn lookup_type_for_child_element( + &self, + name: &str, + tr: &TypeRegister, + ) -> Result { + match self { + Type::Component(component) => { + return component + .root_element + .borrow() + .base_type + .lookup_type_for_child_element(name, tr) + } + Type::Builtin(builtin) => { + if let Some(child_type) = builtin.additional_accepted_child_types.get(name) { + return Ok(child_type.clone()); + } + if builtin.disallow_global_types_as_child_elements { + let mut valid_children: Vec<_> = + builtin.additional_accepted_child_types.keys().cloned().collect(); + valid_children.sort(); + + return Err(format!( + "{} is not allowed within {}. Only {} are valid children", + name, + builtin.native_class.class_name, + valid_children.join(" ") + )); + } + } + _ => {} + }; + tr.lookup_element(name) + } + + pub fn lookup_member_function(&self, name: &str) -> Expression { + match self { + Type::Builtin(builtin) => builtin.member_functions.get(name).unwrap().clone(), + _ => Expression::Invalid, + } + } + + /// Assume this is a builtin type, panic if it isn't + pub fn as_builtin(&self) -> &BuiltinElement { + match self { + Type::Builtin(b) => &b, + Type::Component(_) => panic!("This should not happen because of inlining"), + _ => panic!("invalid type"), + } + } + + /// Assume this is a builtin type, panic if it isn't + pub fn as_native(&self) -> &NativeClass { + match self { + Type::Native(b) => &b, + Type::Component(_) => { + panic!("This should not happen because of native class resolution") + } + _ => panic!("invalid type"), + } + } + + /// Assime it is a Component, panic if it isn't + pub fn as_component(&self) -> &Rc { + match self { + Type::Component(c) => c, + _ => panic!("should be a component because of the repeater_component pass"), + } + } + + /// Return true if the type can be converted to the other type + pub fn can_convert(&self, other: &Self) -> bool { + let can_convert_object = |a: &BTreeMap, b: &BTreeMap| { + // the object `b` has property that the object `a` doesn't + let mut has_more_property = false; + for (k, v) in b { + match a.get(k) { + Some(t) if !t.can_convert(v) => return false, + None => has_more_property = true, + _ => (), + } + } + if has_more_property { + // we should reject the conversion if `a` has property that `b` doesn't have + if a.keys().any(|k| !b.contains_key(k)) { + return false; + } + } + true + }; + let can_convert_object_to_component = |a: &BTreeMap, c: &Component| { + let root_element = c.root_element.borrow(); + if root_element.base_type != Type::Void { + //component is not a struct + return false; + } + for (k, v) in &root_element.property_declarations { + if !a.get(k).map_or(false, |t| t.can_convert(&v.property_type)) { + return false; + } + } + true + }; + + match (self, other) { + (a, b) if a == b => true, + (_, Type::Invalid) + | (_, Type::Void) + | (Type::Float32, Type::Int32) + | (Type::Float32, Type::String) + | (Type::Int32, Type::Float32) + | (Type::Int32, Type::String) + | (Type::Array(_), Type::Model) + | (Type::Float32, Type::Model) + | (Type::Int32, Type::Model) + | (Type::Length, Type::LogicalLength) + | (Type::LogicalLength, Type::Length) + | (Type::Percent, Type::Float32) => true, + (Type::Object(a), Type::Object(b)) if can_convert_object(a, b) => true, + (Type::Object(a), Type::Component(c)) if can_convert_object_to_component(a, c) => true, + _ => false, + } + } + + pub fn collect_contextual_types( + &self, + context_restricted_types: &mut HashMap>, + ) { + let builtin = match self { + Type::Builtin(ty) => ty, + _ => return, + }; + for (accepted_child_type_name, accepted_child_type) in + builtin.additional_accepted_child_types.iter() + { + context_restricted_types + .entry(accepted_child_type_name.clone()) + .or_default() + .insert(builtin.native_class.class_name.clone()); + + accepted_child_type.collect_contextual_types(context_restricted_types); + } + } + + /// If this is a number type which should be used with an unit, this returns the default unit + /// otherwise, returns None + pub fn default_unit(&self) -> Option { + match self { + Type::Duration => Some(Unit::Ms), + Type::Length => Some(Unit::Phx), + Type::LogicalLength => Some(Unit::Px), + Type::Percent => Some(Unit::Percent), + Type::Invalid => None, + Type::Void => None, + Type::Component(_) => None, + Type::Builtin(_) => None, + Type::Native(_) => None, + Type::Signal { .. } => None, + Type::Function { .. } => None, + Type::Float32 => None, + Type::Int32 => None, + Type::String => None, + Type::Color => None, + Type::Resource => None, + Type::Bool => None, + Type::Model => None, + Type::PathElements => None, + Type::Easing => None, + Type::Array(_) => None, + Type::Object(_) => None, + Type::Enumeration(_) => None, + Type::EnumerationValue(_) => None, + Type::ElementReference => None, + } + } +} + +impl Default for Type { + fn default() -> Self { + Self::Invalid + } +} + +#[derive(Debug, Clone, Default)] +pub struct NativeClass { + pub parent: Option>, + pub class_name: String, + pub vtable_symbol: String, + pub properties: HashMap, + pub cpp_type: Option, + pub rust_type_constructor: Option, +} + +impl NativeClass { + pub fn new(class_name: &str) -> Self { + let vtable_symbol = format!("{}VTable", class_name); + Self { + class_name: class_name.into(), + vtable_symbol, + properties: Default::default(), + ..Default::default() + } + } + + pub fn new_with_properties( + class_name: &str, + properties: impl IntoIterator, + ) -> Self { + let mut class = Self::new(class_name); + class.properties = properties.into_iter().collect(); + class + } + + pub fn property_count(&self) -> usize { + self.properties.len() + self.parent.clone().map(|p| p.property_count()).unwrap_or_default() + } + + pub fn local_property_iter(&self) -> impl Iterator { + self.properties.iter() + } + + pub fn visit_class_hierarchy(self: Rc, mut visitor: impl FnMut(&Rc)) { + visitor(&self); + if let Some(parent_class) = &self.parent { + parent_class.clone().visit_class_hierarchy(visitor) + } + } + + pub fn lookup_property(&self, name: &str) -> Option { + if let Some(ty) = self.properties.get(name) { + Some(ty.clone()) + } else if let Some(parent_class) = &self.parent { + parent_class.lookup_property(name) + } else { + None + } + } + + fn lookup_property_distance(self: Rc, name: &str) -> (usize, Rc) { + let mut distance = 0; + let mut class = self.clone(); + loop { + if class.properties.contains_key(name) { + return (distance, class); + } + distance += 1; + class = class.parent.as_ref().unwrap().clone(); + } + } + + pub fn select_minimal_class_based_on_property_usage<'a>( + self: Rc, + properties_used: impl Iterator, + ) -> Rc { + let (_min_distance, minimal_class) = properties_used.fold( + (std::usize::MAX, self.clone()), + |(current_distance, current_class), prop_name| { + let (prop_distance, prop_class) = self.clone().lookup_property_distance(&prop_name); + + if prop_distance < current_distance { + (prop_distance, prop_class) + } else { + (current_distance, current_class) + } + }, + ); + minimal_class + } +} + +#[derive(Debug, Clone, Default)] +pub struct BuiltinElement { + pub native_class: Rc, + pub properties: HashMap, + pub default_bindings: HashMap, + pub additional_accepted_child_types: HashMap, + pub disallow_global_types_as_child_elements: bool, + /// Non-item type do not have reserved properties (x/width/rowspan/...) added to them (eg: PropertyAnimation) + pub is_non_item_type: bool, + pub member_functions: HashMap, +} + +impl BuiltinElement { + pub fn new(native_class: Rc) -> Self { + let mut properties = HashMap::new(); + native_class.clone().visit_class_hierarchy(|class| { + for (prop_name, prop_type) in class.local_property_iter() { + properties.insert(prop_name.clone(), prop_type.clone()); + } + }); + Self { native_class, properties, ..Default::default() } + } +} + +#[test] +fn test_select_minimal_class_based_on_property_usage() { + let first = Rc::new(NativeClass::new_with_properties( + "first_class", + [("first_prop".to_owned(), Type::Int32)].iter().cloned(), + )); + + let mut second = NativeClass::new_with_properties( + "second_class", + [("second_prop".to_owned(), Type::Int32)].iter().cloned(), + ); + second.parent = Some(first.clone()); + let second = Rc::new(second); + + let reduce_to_first = second + .clone() + .select_minimal_class_based_on_property_usage(["first_prop".to_owned()].iter()); + + assert_eq!(reduce_to_first.class_name, first.class_name); + + let reduce_to_second = second + .clone() + .select_minimal_class_based_on_property_usage(["second_prop".to_owned()].iter()); + + assert_eq!(reduce_to_second.class_name, second.class_name); + + let reduce_to_second = second.clone().select_minimal_class_based_on_property_usage( + ["first_prop".to_owned(), "second_prop".to_owned()].iter(), + ); + + assert_eq!(reduce_to_second.class_name, second.class_name); +} + +#[derive(Debug, Clone)] +pub struct Enumeration { + pub name: String, + pub values: Vec, + pub default_value: usize, // index in values +} + +impl PartialEq for Enumeration { + fn eq(&self, other: &Self) -> bool { + self.name.eq(&other.name) + } +} + +impl Enumeration { + pub fn default_value(self: Rc) -> EnumerationValue { + EnumerationValue { value: self.default_value, enumeration: self.clone() } + } + + pub fn try_value_from_string(self: Rc, value: &str) -> Option { + self.values.iter().enumerate().find_map(|(idx, name)| { + if name == value { + Some(EnumerationValue { value: idx, enumeration: self.clone() }) + } else { + None + } + }) + } +} + +#[derive(Clone, Debug)] +pub struct EnumerationValue { + pub value: usize, // index in enumeration.values + pub enumeration: Rc, +} + +impl PartialEq for EnumerationValue { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.enumeration, &other.enumeration) && self.value == other.value + } +} + +impl std::fmt::Display for EnumerationValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.enumeration.values[self.value].fmt(f) + } +} diff --git a/sixtyfps_compiler/layout.rs b/sixtyfps_compiler/layout.rs index 39722193d..6715e0b19 100644 --- a/sixtyfps_compiler/layout.rs +++ b/sixtyfps_compiler/layout.rs @@ -10,8 +10,9 @@ LICENSE END */ //! Datastructures used to represent layouts in the compiler use crate::expression_tree::{Expression, NamedReference, Path}; +use crate::langtype::Type; use crate::object_tree::{ElementRc, PropertyDeclaration}; -use crate::{passes::ExpressionFieldsVisitor, typeregister::Type}; +use crate::passes::ExpressionFieldsVisitor; use std::rc::Rc; #[derive(Debug, derive_more::From)] diff --git a/sixtyfps_compiler/lib.rs b/sixtyfps_compiler/lib.rs index 7444a2833..dfa18d355 100644 --- a/sixtyfps_compiler/lib.rs +++ b/sixtyfps_compiler/lib.rs @@ -27,6 +27,7 @@ use std::{borrow::Cow, cell::RefCell, rc::Rc}; pub mod diagnostics; pub mod expression_tree; pub mod generator; +pub mod langtype; pub mod layout; pub mod lexer; pub mod object_tree; diff --git a/sixtyfps_compiler/object_tree.rs b/sixtyfps_compiler/object_tree.rs index 713e5ff19..31b3ce0dd 100644 --- a/sixtyfps_compiler/object_tree.rs +++ b/sixtyfps_compiler/object_tree.rs @@ -13,8 +13,9 @@ LICENSE END */ use crate::diagnostics::{FileDiagnostics, Spanned, SpannedWithSourceFile}; use crate::expression_tree::{Expression, ExpressionSpanned, NamedReference}; +use crate::langtype::{NativeClass, Type}; use crate::parser::{identifier_text, syntax_nodes, SyntaxKind, SyntaxNodeWithSourceFile}; -use crate::typeregister::{NativeClass, Type, TypeRegister}; +use crate::typeregister::TypeRegister; use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::rc::{Rc, Weak}; @@ -160,7 +161,7 @@ pub struct Element { /// The id are then re-assigned unique id in the assign_id pass pub id: String, //pub base: QualifiedTypeName, - pub base_type: crate::typeregister::Type, + pub base_type: crate::langtype::Type, /// Currently contains also the signals. FIXME: should that be changed? pub bindings: HashMap, pub children: Vec, diff --git a/sixtyfps_compiler/passes/compile_paths.rs b/sixtyfps_compiler/passes/compile_paths.rs index 46a652f37..c2a67ffd6 100644 --- a/sixtyfps_compiler/passes/compile_paths.rs +++ b/sixtyfps_compiler/passes/compile_paths.rs @@ -16,8 +16,8 @@ use crate::diagnostics::BuildDiagnostics; /// elements property of the Path element. That way the generators have to deal /// with path embedding only as part of the property assignment. use crate::expression_tree::*; +use crate::langtype::Type; use crate::object_tree::*; -use crate::typeregister::Type; use std::rc::Rc; pub fn compile_paths( @@ -32,12 +32,12 @@ pub fn compile_paths( recurse_elem(&component.root_element, &(), &mut |elem_, _| { let accepted_type = match &elem_.borrow().base_type { - crate::typeregister::Type::Builtin(be) + Type::Builtin(be) if be.native_class.class_name == path_type.native_class.class_name => { path_type } - crate::typeregister::Type::Builtin(be) + Type::Builtin(be) if be.native_class.class_name == pathlayout_type.native_class.class_name => { pathlayout_type diff --git a/sixtyfps_compiler/passes/deduplicate_property_read.rs b/sixtyfps_compiler/passes/deduplicate_property_read.rs index 4cfbc037d..4d8d0de75 100644 --- a/sixtyfps_compiler/passes/deduplicate_property_read.rs +++ b/sixtyfps_compiler/passes/deduplicate_property_read.rs @@ -10,8 +10,8 @@ LICENSE END */ //! Do not read twice the same property, store in a local variable instead use crate::expression_tree::*; +use crate::langtype::Type; use crate::object_tree::*; -use crate::typeregister::Type; use std::{cell::RefCell, collections::HashMap}; pub fn deduplicate_property_read(component: &Component) { diff --git a/sixtyfps_compiler/passes/inlining.rs b/sixtyfps_compiler/passes/inlining.rs index f63043b43..12e6c03ee 100644 --- a/sixtyfps_compiler/passes/inlining.rs +++ b/sixtyfps_compiler/passes/inlining.rs @@ -9,11 +9,9 @@ LICENSE END */ //! Inline each object_tree::Component within the main Component -use crate::{ - expression_tree::{Expression, NamedReference}, - object_tree::*, - typeregister::Type, -}; +use crate::expression_tree::{Expression, NamedReference}; +use crate::langtype::Type; +use crate::object_tree::*; use by_address::ByAddress; use std::cell::RefCell; use std::collections::HashMap; diff --git a/sixtyfps_compiler/passes/lower_layout.rs b/sixtyfps_compiler/passes/lower_layout.rs index ea3dbfdc0..2e4097c5b 100644 --- a/sixtyfps_compiler/passes/lower_layout.rs +++ b/sixtyfps_compiler/passes/lower_layout.rs @@ -11,8 +11,9 @@ LICENSE END */ use crate::diagnostics::BuildDiagnostics; use crate::expression_tree::*; +use crate::langtype::Type; use crate::layout::*; -use crate::{object_tree::*, typeregister::Type}; +use crate::object_tree::*; use std::rc::Rc; fn property_reference(element: &ElementRc, name: &str) -> Box { diff --git a/sixtyfps_compiler/passes/lower_states.rs b/sixtyfps_compiler/passes/lower_states.rs index f14b2909f..6e72b31a8 100644 --- a/sixtyfps_compiler/passes/lower_states.rs +++ b/sixtyfps_compiler/passes/lower_states.rs @@ -11,8 +11,8 @@ LICENSE END */ use crate::diagnostics::BuildDiagnostics; use crate::expression_tree::*; +use crate::langtype::Type; use crate::object_tree::*; -use crate::typeregister::Type; use std::rc::Rc; pub fn lower_states(component: &Rc, diag: &mut BuildDiagnostics) { diff --git a/sixtyfps_compiler/passes/materialize_fake_properties.rs b/sixtyfps_compiler/passes/materialize_fake_properties.rs index e8cedc31e..b836d1ca9 100644 --- a/sixtyfps_compiler/passes/materialize_fake_properties.rs +++ b/sixtyfps_compiler/passes/materialize_fake_properties.rs @@ -10,8 +10,8 @@ LICENSE END */ //! This pass creates properties that are used but are otherwise not real use crate::expression_tree::NamedReference; +use crate::langtype::Type; use crate::object_tree::*; -use crate::typeregister::Type; use std::collections::HashMap; use std::rc::Rc; @@ -46,11 +46,9 @@ fn maybe_materialize( return; } let has_declared_property = match &base_type { - crate::typeregister::Type::Component(c) => { - has_declared_property(&c.root_element.borrow(), prop) - } - crate::typeregister::Type::Builtin(b) => b.properties.contains_key(prop), - crate::typeregister::Type::Native(n) => n.lookup_property(prop).is_some(), + Type::Component(c) => has_declared_property(&c.root_element.borrow(), prop), + Type::Builtin(b) => b.properties.contains_key(prop), + Type::Native(n) => n.lookup_property(prop).is_some(), _ => false, }; @@ -72,11 +70,9 @@ fn has_declared_property(elem: &Element, prop: &str) -> bool { return true; } match &elem.base_type { - crate::typeregister::Type::Component(c) => { - has_declared_property(&c.root_element.borrow(), prop) - } - crate::typeregister::Type::Builtin(b) => b.properties.contains_key(prop), - crate::typeregister::Type::Native(n) => n.lookup_property(prop).is_some(), + Type::Component(c) => has_declared_property(&c.root_element.borrow(), prop), + Type::Builtin(b) => b.properties.contains_key(prop), + Type::Native(n) => n.lookup_property(prop).is_some(), _ => false, } } diff --git a/sixtyfps_compiler/passes/move_declarations.rs b/sixtyfps_compiler/passes/move_declarations.rs index 5869aa130..f215b9929 100644 --- a/sixtyfps_compiler/passes/move_declarations.rs +++ b/sixtyfps_compiler/passes/move_declarations.rs @@ -9,13 +9,12 @@ LICENSE END */ //! This pass moves all declaration of properties or signal to the root -use crate::{ - diagnostics::{BuildDiagnostics, Level}, - expression_tree::{Expression, NamedReference}, - object_tree::*, - passes::ExpressionFieldsVisitor, - typeregister::Type, -}; +use crate::diagnostics::{BuildDiagnostics, Level}; +use crate::expression_tree::{Expression, NamedReference}; +use crate::langtype::Type; +use crate::object_tree::*; +use crate::passes::ExpressionFieldsVisitor; + use std::collections::HashMap; use std::rc::Rc; diff --git a/sixtyfps_compiler/passes/repeater_component.rs b/sixtyfps_compiler/passes/repeater_component.rs index 5fac8aac7..113a23830 100644 --- a/sixtyfps_compiler/passes/repeater_component.rs +++ b/sixtyfps_compiler/passes/repeater_component.rs @@ -12,8 +12,8 @@ Make sure that the Repeated expression are just components without any chilodren */ use crate::expression_tree::NamedReference; +use crate::langtype::Type; use crate::object_tree::*; -use crate::typeregister::Type; use std::{cell::RefCell, rc::Rc}; pub fn process_repeater_components(component: &Rc) { diff --git a/sixtyfps_compiler/passes/resolve_native_classes.rs b/sixtyfps_compiler/passes/resolve_native_classes.rs index 98f931842..710b420eb 100644 --- a/sixtyfps_compiler/passes/resolve_native_classes.rs +++ b/sixtyfps_compiler/passes/resolve_native_classes.rs @@ -10,8 +10,8 @@ LICENSE END */ //! After inlining and moving declarations, all Element::base_type should be Type::BuiltinElement. This pass resolves them // to NativeClass and picking a variant that only contains the used properties. +use crate::langtype::Type; use crate::object_tree::{recurse_elem, Component}; -use crate::typeregister::Type; pub fn resolve_native_classes(component: &Component) { recurse_elem(&component.root_element, &(), &mut |elem, _| { diff --git a/sixtyfps_compiler/passes/resolving.rs b/sixtyfps_compiler/passes/resolving.rs index 8b95d79ae..eb0d75b11 100644 --- a/sixtyfps_compiler/passes/resolving.rs +++ b/sixtyfps_compiler/passes/resolving.rs @@ -16,9 +16,9 @@ LICENSE END */ use crate::diagnostics::BuildDiagnostics; use crate::expression_tree::*; +use crate::langtype::Type; use crate::object_tree::*; use crate::parser::{identifier_text, syntax_nodes, SyntaxKind, SyntaxNodeWithSourceFile}; -use crate::typeregister::Type; use by_address::ByAddress; use std::{collections::HashMap, collections::HashSet, rc::Rc}; diff --git a/sixtyfps_compiler/typeregister.rs b/sixtyfps_compiler/typeregister.rs index acd324483..edbb05022 100644 --- a/sixtyfps_compiler/typeregister.rs +++ b/sixtyfps_compiler/typeregister.rs @@ -7,495 +7,13 @@ This file is also available under commercial licensing terms. Please contact info@sixtyfps.io for more information. LICENSE END */ -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::{cell::RefCell, fmt::Display, rc::Rc}; +use std::collections::{HashMap, HashSet}; +use std::{cell::RefCell, rc::Rc}; use crate::expression_tree::{BuiltinFunction, Expression, Unit}; +use crate::langtype::{BuiltinElement, Enumeration, NativeClass, Type}; use crate::object_tree::{Component, Element}; -#[derive(Debug, Clone)] -pub enum Type { - /// Correspond to an uninitialized type, or an error - Invalid, - /// The type of an expression that return nothing - Void, - Component(Rc), - Builtin(Rc), - Native(Rc), - - Signal { - args: Vec, - }, - Function { - return_type: Box, - args: Vec, - }, - - // Other property types: - Float32, - Int32, - String, - Color, - Duration, - Length, - LogicalLength, - Percent, - Resource, - Bool, - Model, - PathElements, - Easing, - - Array(Box), - Object(BTreeMap), - - Enumeration(Rc), - EnumerationValue(EnumerationValue), - - ElementReference, -} - -impl core::cmp::PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - match self { - Type::Invalid => matches!(other, Type::Invalid), - Type::Void => matches!(other, Type::Void), - Type::Component(a) => matches!(other, Type::Component(b) if Rc::ptr_eq(a, b)), - Type::Builtin(a) => matches!(other, Type::Builtin(b) if Rc::ptr_eq(a, b)), - Type::Native(a) => matches!(other, Type::Native(b) if Rc::ptr_eq(a, b)), - Type::Signal { args: a } => matches!(other, Type::Signal { args: b } if a == b), - Type::Function { return_type: lhs_rt, args: lhs_args } => { - matches!(other, Type::Function { return_type: rhs_rt, args: rhs_args } if lhs_rt == rhs_rt && lhs_args == rhs_args) - } - Type::Float32 => matches!(other, Type::Float32), - Type::Int32 => matches!(other, Type::Int32), - Type::String => matches!(other, Type::String), - Type::Color => matches!(other, Type::Color), - Type::Duration => matches!(other, Type::Duration), - Type::Length => matches!(other, Type::Length), - Type::LogicalLength => matches!(other, Type::LogicalLength), - Type::Percent => matches!(other, Type::Percent), - Type::Resource => matches!(other, Type::Resource), - Type::Bool => matches!(other, Type::Bool), - Type::Model => matches!(other, Type::Model), - Type::PathElements => matches!(other, Type::PathElements), - Type::Easing => matches!(other, Type::Easing), - Type::Array(a) => matches!(other, Type::Array(b) if a == b), - Type::Object(a) => matches!(other, Type::Object(b) if a == b), - Type::Enumeration(lhs) => matches!(other, Type::Enumeration(rhs) if lhs == rhs), - Type::EnumerationValue(lhs) => { - matches!(other, Type::EnumerationValue(rhs) if lhs == rhs) - } - Type::ElementReference => matches!(other, Type::ElementReference), - } - } -} - -impl Display for Type { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Type::Invalid => write!(f, ""), - Type::Void => write!(f, "void"), - Type::Component(c) => c.id.fmt(f), - Type::Builtin(b) => b.native_class.class_name.fmt(f), - Type::Native(b) => b.class_name.fmt(f), - Type::Signal { args } => { - write!(f, "signal")?; - if !args.is_empty() { - write!(f, "(")?; - for (i, arg) in args.iter().enumerate() { - if i > 0 { - write!(f, ",")?; - } - write!(f, "{}", arg)?; - } - write!(f, ")")? - } - Ok(()) - } - Type::Function { return_type, args } => { - write!(f, "function(")?; - for (i, arg) in args.iter().enumerate() { - if i > 0 { - write!(f, ",")?; - } - write!(f, "{}", arg)?; - } - write!(f, ") -> {}", return_type) - } - Type::Float32 => write!(f, "float"), - Type::Int32 => write!(f, "int"), - Type::String => write!(f, "string"), - Type::Duration => write!(f, "duration"), - Type::Length => write!(f, "length"), - Type::LogicalLength => write!(f, "logical_length"), - Type::Percent => write!(f, "percent"), - Type::Color => write!(f, "color"), - Type::Resource => write!(f, "resource"), - Type::Bool => write!(f, "bool"), - Type::Model => write!(f, "model"), - Type::Array(t) => write!(f, "[{}]", t), - Type::Object(t) => { - write!(f, "{{ ")?; - for (k, v) in t { - write!(f, "{}: {},", k, v)?; - } - write!(f, "}}") - } - Type::PathElements => write!(f, "pathelements"), - Type::Easing => write!(f, "easing"), - Type::Enumeration(enumeration) => write!(f, "enum {}", enumeration.name), - Type::EnumerationValue(value) => { - write!(f, "enum {}::{}", value.enumeration.name, value.to_string()) - } - Type::ElementReference => write!(f, "element ref"), - } - } -} - -impl Type { - pub fn is_object_type(&self) -> bool { - matches!(self, Self::Component(_) | Self::Builtin(_)) - } - - /// valid type for properties - pub fn is_property_type(&self) -> bool { - match self { - Self::Float32 - | Self::Int32 - | Self::String - | Self::Color - | Self::Duration - | Self::Length - | Self::LogicalLength - | Self::Percent - | Self::Resource - | Self::Bool - | Self::Model - | Self::Easing - | Self::Enumeration(_) - | Self::ElementReference - | Self::Object(_) - | Self::Array(_) => true, - Self::Component(c) => c.root_element.borrow().base_type == Type::Void, - _ => false, - } - } - - pub fn ok_for_public_api(&self) -> bool { - // Duration and Easing don't have good types for public API exposure yet. - !matches!(self, Self::Duration | Self::Easing) - } - - pub fn lookup_property(&self, name: &str) -> Type { - match self { - Type::Component(c) => c.root_element.borrow().lookup_property(name), - Type::Builtin(b) => b.properties.get(name).cloned().unwrap_or_else(|| { - if b.is_non_item_type { - Type::Invalid - } else { - reserved_property(name) - } - }), - Type::Native(n) => n.lookup_property(name).unwrap_or_default(), - _ => Type::Invalid, - } - } - - pub fn lookup_type_for_child_element( - &self, - name: &str, - tr: &TypeRegister, - ) -> Result { - match self { - Type::Component(component) => { - return component - .root_element - .borrow() - .base_type - .lookup_type_for_child_element(name, tr) - } - Type::Builtin(builtin) => { - if let Some(child_type) = builtin.additional_accepted_child_types.get(name) { - return Ok(child_type.clone()); - } - if builtin.disallow_global_types_as_child_elements { - let mut valid_children: Vec<_> = - builtin.additional_accepted_child_types.keys().cloned().collect(); - valid_children.sort(); - - return Err(format!( - "{} is not allowed within {}. Only {} are valid children", - name, - builtin.native_class.class_name, - valid_children.join(" ") - )); - } - } - _ => {} - }; - tr.lookup_element(name) - } - - pub fn lookup_member_function(&self, name: &str) -> Expression { - match self { - Type::Builtin(builtin) => builtin.member_functions.get(name).unwrap().clone(), - _ => Expression::Invalid, - } - } - - /// Assume this is a builtin type, panic if it isn't - pub fn as_builtin(&self) -> &BuiltinElement { - match self { - Type::Builtin(b) => &b, - Type::Component(_) => panic!("This should not happen because of inlining"), - _ => panic!("invalid type"), - } - } - - /// Assume this is a builtin type, panic if it isn't - pub fn as_native(&self) -> &NativeClass { - match self { - Type::Native(b) => &b, - Type::Component(_) => { - panic!("This should not happen because of native class resolution") - } - _ => panic!("invalid type"), - } - } - - /// Assime it is a Component, panic if it isn't - pub fn as_component(&self) -> &Rc { - match self { - Type::Component(c) => c, - _ => panic!("should be a component because of the repeater_component pass"), - } - } - - /// Return true if the type can be converted to the other type - pub fn can_convert(&self, other: &Self) -> bool { - let can_convert_object = |a: &BTreeMap, b: &BTreeMap| { - // the object `b` has property that the object `a` doesn't - let mut has_more_property = false; - for (k, v) in b { - match a.get(k) { - Some(t) if !t.can_convert(v) => return false, - None => has_more_property = true, - _ => (), - } - } - if has_more_property { - // we should reject the conversion if `a` has property that `b` doesn't have - if a.keys().any(|k| !b.contains_key(k)) { - return false; - } - } - true - }; - let can_convert_object_to_component = |a: &BTreeMap, c: &Component| { - let root_element = c.root_element.borrow(); - if root_element.base_type != Type::Void { - //component is not a struct - return false; - } - for (k, v) in &root_element.property_declarations { - if !a.get(k).map_or(false, |t| t.can_convert(&v.property_type)) { - return false; - } - } - true - }; - - match (self, other) { - (a, b) if a == b => true, - (_, Type::Invalid) - | (_, Type::Void) - | (Type::Float32, Type::Int32) - | (Type::Float32, Type::String) - | (Type::Int32, Type::Float32) - | (Type::Int32, Type::String) - | (Type::Array(_), Type::Model) - | (Type::Float32, Type::Model) - | (Type::Int32, Type::Model) - | (Type::Length, Type::LogicalLength) - | (Type::LogicalLength, Type::Length) - | (Type::Percent, Type::Float32) => true, - (Type::Object(a), Type::Object(b)) if can_convert_object(a, b) => true, - (Type::Object(a), Type::Component(c)) if can_convert_object_to_component(a, c) => true, - _ => false, - } - } - - fn collect_contextual_types( - &self, - context_restricted_types: &mut HashMap>, - ) { - let builtin = match self { - Type::Builtin(ty) => ty, - _ => return, - }; - for (accepted_child_type_name, accepted_child_type) in - builtin.additional_accepted_child_types.iter() - { - context_restricted_types - .entry(accepted_child_type_name.clone()) - .or_default() - .insert(builtin.native_class.class_name.clone()); - - accepted_child_type.collect_contextual_types(context_restricted_types); - } - } - - /// If this is a number type which should be used with an unit, this returns the default unit - /// otherwise, returns None - pub fn default_unit(&self) -> Option { - match self { - Type::Duration => Some(Unit::Ms), - Type::Length => Some(Unit::Phx), - Type::LogicalLength => Some(Unit::Px), - Type::Percent => Some(Unit::Percent), - Type::Invalid => None, - Type::Void => None, - Type::Component(_) => None, - Type::Builtin(_) => None, - Type::Native(_) => None, - Type::Signal { .. } => None, - Type::Function { .. } => None, - Type::Float32 => None, - Type::Int32 => None, - Type::String => None, - Type::Color => None, - Type::Resource => None, - Type::Bool => None, - Type::Model => None, - Type::PathElements => None, - Type::Easing => None, - Type::Array(_) => None, - Type::Object(_) => None, - Type::Enumeration(_) => None, - Type::EnumerationValue(_) => None, - Type::ElementReference => None, - } - } -} - -impl Default for Type { - fn default() -> Self { - Self::Invalid - } -} - -#[derive(Debug, Clone, Default)] -pub struct NativeClass { - pub parent: Option>, - pub class_name: String, - pub vtable_symbol: String, - pub properties: HashMap, - pub cpp_type: Option, - pub rust_type_constructor: Option, -} - -impl NativeClass { - pub fn new(class_name: &str) -> Self { - let vtable_symbol = format!("{}VTable", class_name); - Self { - class_name: class_name.into(), - vtable_symbol, - properties: Default::default(), - ..Default::default() - } - } - - pub fn new_with_properties( - class_name: &str, - properties: impl IntoIterator, - ) -> Self { - let mut class = Self::new(class_name); - class.properties = properties.into_iter().collect(); - class - } - - pub fn property_count(&self) -> usize { - self.properties.len() + self.parent.clone().map(|p| p.property_count()).unwrap_or_default() - } - - pub fn local_property_iter(&self) -> impl Iterator { - self.properties.iter() - } - - pub fn visit_class_hierarchy(self: Rc, mut visitor: impl FnMut(&Rc)) { - visitor(&self); - if let Some(parent_class) = &self.parent { - parent_class.clone().visit_class_hierarchy(visitor) - } - } - - pub fn lookup_property(&self, name: &str) -> Option { - if let Some(ty) = self.properties.get(name) { - Some(ty.clone()) - } else if let Some(parent_class) = &self.parent { - parent_class.lookup_property(name) - } else { - None - } - } - - fn lookup_property_distance(self: Rc, name: &str) -> (usize, Rc) { - let mut distance = 0; - let mut class = self.clone(); - loop { - if class.properties.contains_key(name) { - return (distance, class); - } - distance += 1; - class = class.parent.as_ref().unwrap().clone(); - } - } - - pub fn select_minimal_class_based_on_property_usage<'a>( - self: Rc, - properties_used: impl Iterator, - ) -> Rc { - let (_min_distance, minimal_class) = properties_used.fold( - (std::usize::MAX, self.clone()), - |(current_distance, current_class), prop_name| { - let (prop_distance, prop_class) = self.clone().lookup_property_distance(&prop_name); - - if prop_distance < current_distance { - (prop_distance, prop_class) - } else { - (current_distance, current_class) - } - }, - ); - minimal_class - } -} - -#[derive(Debug, Clone, Default)] -pub struct BuiltinElement { - pub native_class: Rc, - pub properties: HashMap, - pub default_bindings: HashMap, - pub additional_accepted_child_types: HashMap, - pub disallow_global_types_as_child_elements: bool, - /// Non-item type do not have reserved properties (x/width/rowspan/...) added to them (eg: PropertyAnimation) - pub is_non_item_type: bool, - pub member_functions: HashMap, -} - -impl BuiltinElement { - pub fn new(native_class: Rc) -> Self { - let mut properties = HashMap::new(); - native_class.clone().visit_class_hierarchy(|class| { - for (prop_name, prop_type) in class.local_property_iter() { - properties.insert(prop_name.clone(), prop_type.clone()); - } - }); - Self { native_class, properties, ..Default::default() } - } -} - /// reserved property injected in every item pub fn reserved_property(name: &str) -> Type { for (p, t) in [ @@ -1069,83 +587,3 @@ impl TypeRegister { } } } - -#[test] -fn test_select_minimal_class_based_on_property_usage() { - let first = Rc::new(NativeClass::new_with_properties( - "first_class", - [("first_prop".to_owned(), Type::Int32)].iter().cloned(), - )); - - let mut second = NativeClass::new_with_properties( - "second_class", - [("second_prop".to_owned(), Type::Int32)].iter().cloned(), - ); - second.parent = Some(first.clone()); - let second = Rc::new(second); - - let reduce_to_first = second - .clone() - .select_minimal_class_based_on_property_usage(["first_prop".to_owned()].iter()); - - assert_eq!(reduce_to_first.class_name, first.class_name); - - let reduce_to_second = second - .clone() - .select_minimal_class_based_on_property_usage(["second_prop".to_owned()].iter()); - - assert_eq!(reduce_to_second.class_name, second.class_name); - - let reduce_to_second = second.clone().select_minimal_class_based_on_property_usage( - ["first_prop".to_owned(), "second_prop".to_owned()].iter(), - ); - - assert_eq!(reduce_to_second.class_name, second.class_name); -} - -#[derive(Debug, Clone)] -pub struct Enumeration { - pub name: String, - pub values: Vec, - pub default_value: usize, // index in values -} - -impl PartialEq for Enumeration { - fn eq(&self, other: &Self) -> bool { - self.name.eq(&other.name) - } -} - -impl Enumeration { - pub fn default_value(self: Rc) -> EnumerationValue { - EnumerationValue { value: self.default_value, enumeration: self.clone() } - } - - pub fn try_value_from_string(self: Rc, value: &str) -> Option { - self.values.iter().enumerate().find_map(|(idx, name)| { - if name == value { - Some(EnumerationValue { value: idx, enumeration: self.clone() }) - } else { - None - } - }) - } -} - -#[derive(Clone, Debug)] -pub struct EnumerationValue { - pub value: usize, // index in enumeration.values - pub enumeration: Rc, -} - -impl PartialEq for EnumerationValue { - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.enumeration, &other.enumeration) && self.value == other.value - } -} - -impl std::fmt::Display for EnumerationValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.enumeration.values[self.value].fmt(f) - } -} diff --git a/sixtyfps_runtime/interpreter/dynamic_component.rs b/sixtyfps_runtime/interpreter/dynamic_component.rs index d93dde9d8..e94e16f64 100644 --- a/sixtyfps_runtime/interpreter/dynamic_component.rs +++ b/sixtyfps_runtime/interpreter/dynamic_component.rs @@ -15,10 +15,10 @@ use dynamic_type::{Instance, InstanceBox}; use expression_tree::NamedReference; use object_tree::{Element, ElementRc}; use sixtyfps_compilerlib::expression_tree::Expression; +use sixtyfps_compilerlib::langtype::Type; use sixtyfps_compilerlib::layout::{ GridLayout, Layout, LayoutConstraints, LayoutElement, LayoutItem, PathLayout, }; -use sixtyfps_compilerlib::typeregister::Type; use sixtyfps_compilerlib::*; use sixtyfps_corelib::component::{Component, ComponentRefPin, ComponentVTable}; use sixtyfps_corelib::graphics::Resource; diff --git a/sixtyfps_runtime/interpreter/eval.rs b/sixtyfps_runtime/interpreter/eval.rs index 6c535f1b8..faf8cf24b 100644 --- a/sixtyfps_runtime/interpreter/eval.rs +++ b/sixtyfps_runtime/interpreter/eval.rs @@ -15,7 +15,8 @@ use sixtyfps_compilerlib::expression_tree::{ BuiltinFunction, EasingCurve, Expression, ExpressionSpanned, NamedReference, Path as ExprPath, PathElement as ExprPathElement, }; -use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type}; +use sixtyfps_compilerlib::langtype::Type; +use sixtyfps_compilerlib::object_tree::ElementRc; use sixtyfps_corelib as corelib; use sixtyfps_corelib::{ graphics::PathElement, items::ItemRef, items::PropertyAnimation, Color, PathData, Resource, diff --git a/sixtyfps_runtime/interpreter/lib.rs b/sixtyfps_runtime/interpreter/lib.rs index 30fe97937..ac3d65bf3 100644 --- a/sixtyfps_runtime/interpreter/lib.rs +++ b/sixtyfps_runtime/interpreter/lib.rs @@ -34,7 +34,7 @@ impl<'id> dynamic_component::ComponentDescription<'id> { } /// List of publicly declared properties or signal - pub fn properties(&self) -> HashMap { + pub fn properties(&self) -> HashMap { self.original .root_element .borrow()