Refactoring: split ElementType away from the types used as property type

These are two different concept, and it is confusing to keep them in the
same enum

We want to support component without any base element, and Void is
already used for global component, so do this refactoring before
This commit is contained in:
Olivier Goffart 2022-10-26 12:45:48 +02:00 committed by Olivier Goffart
parent 8fa6bbb244
commit 28ae8f7bc4
51 changed files with 588 additions and 554 deletions

View file

@ -228,13 +228,10 @@ fn to_eval_value<'cx>(
| Type::Void
| Type::InferredProperty
| Type::InferredCallback
| Type::Builtin(_)
| Type::Native(_)
| Type::Function { .. }
| Type::Model
| Type::Callback { .. }
| Type::Easing
| Type::Component(_)
| Type::PathData
| Type::LayoutCache
| Type::ElementReference => cx.throw_error("Cannot convert to a Slint property value"),

View file

@ -220,9 +220,6 @@ fn to_debug_string(
Type::Void
| Type::InferredCallback
| Type::InferredProperty
| Type::Component(_)
| Type::Builtin(_)
| Type::Native(_)
| Type::Callback { .. }
| Type::Function { .. }
| Type::ElementReference

View file

@ -541,7 +541,6 @@ impl Expression {
Type::Struct { fields, .. } => {
fields.get(name.as_str()).unwrap_or(&Type::Invalid).clone()
}
Type::Component(c) => c.root_element.borrow().lookup_property(name).property_type,
_ => Type::Invalid,
},
Expression::ArrayIndex { array, .. } => match array.ty() {
@ -975,22 +974,6 @@ impl Expression {
Expression::Struct { values: new_values, ty: target_type },
]);
}
(Type::Struct { .. }, Type::Component(component)) => {
let struct_type_for_component = Type::Struct {
fields: component
.root_element
.borrow()
.property_declarations
.iter()
.map(|(name, prop_decl)| {
(name.clone(), prop_decl.property_type.clone())
})
.collect(),
name: None,
node: None,
};
self.maybe_convert_to(struct_type_for_component, node, diag)
}
(left, right) => match (left.as_unit_product(), right.as_unit_product()) {
(Some(left), Some(right)) => {
if let Some(power) =
@ -1086,9 +1069,6 @@ impl Expression {
pub fn default_value_for_type(ty: &Type) -> Expression {
match ty {
Type::Invalid
| Type::Component(_)
| Type::Builtin(_)
| Type::Native(_)
| Type::Callback { .. }
| Type::Function { .. }
| Type::Void

View file

@ -11,7 +11,7 @@ use std::collections::{BTreeSet, HashSet, VecDeque};
use std::rc::{Rc, Weak};
use crate::expression_tree::{BindingExpression, Expression};
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::namedreference::NamedReference;
use crate::object_tree::{Component, Document, ElementRc};
@ -65,7 +65,7 @@ pub fn generate(
#![allow(unused_variables)]
#![allow(unreachable_code)]
if matches!(doc.root_component.root_element.borrow().base_type, Type::Invalid | Type::Void) {
if matches!(doc.root_component.root_element.borrow().base_type, ElementType::Error) {
// empty document, nothing to generate
return Ok(());
}
@ -415,10 +415,10 @@ pub fn for_each_const_properties(component: &Rc<Component>, mut f: impl FnMut(&E
.map(|(k, _)| k.clone()),
);
match &e.clone().borrow().base_type {
Type::Component(c) => {
ElementType::Component(c) => {
e = c.root_element.clone();
}
Type::Native(n) => {
ElementType::Native(n) => {
let mut n = n;
loop {
all_prop.extend(
@ -438,7 +438,10 @@ pub fn for_each_const_properties(component: &Rc<Component>, mut f: impl FnMut(&E
}
break;
}
_ => break,
ElementType::Builtin(_) => {
unreachable!("builtin element should have been resolved")
}
ElementType::Global | ElementType::Error => break,
}
}
for c in all_prop {

View file

@ -332,7 +332,6 @@ impl CppType for Type {
Type::Array(i) => Some(format!("std::shared_ptr<slint::Model<{}>>", i.cpp_type()?)),
Type::Image => Some("slint::Image".to_owned()),
Type::Builtin(elem) => elem.native_class.cpp_type.clone(),
Type::Enumeration(enumeration) => {
Some(format!("slint::cbindgen_private::{}", ident(&enumeration.name)))
}

View file

@ -13,7 +13,7 @@ Some convention used in the generated code:
*/
use crate::expression_tree::{BuiltinFunction, EasingCurve, OperatorClass};
use crate::langtype::Type;
use crate::langtype::{ElementType, Type};
use crate::layout::Orientation;
use crate::llr::{
self, EvaluationContext as llr_EvaluationContext, Expression, ParentCtx as llr_ParentCtx,
@ -130,7 +130,7 @@ fn set_primitive_property_value(ty: &Type, value_expression: TokenStream) -> Tok
/// Generate the rust code for the given component.
pub fn generate(doc: &Document) -> TokenStream {
if matches!(doc.root_component.root_element.borrow().base_type, Type::Invalid | Type::Void) {
if matches!(doc.root_component.root_element.borrow().base_type, ElementType::Error) {
// empty document, nothing to generate
return TokenStream::default();
}
@ -1653,15 +1653,6 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
(Type::Brush, Type::Color) => {
quote!(#f.color())
}
(Type::Struct { ref fields, .. }, Type::Component(c)) => {
let fields = fields.iter().enumerate().map(|(index, (name, _))| {
let index = proc_macro2::Literal::usize_unsuffixed(index);
let name = ident(name);
quote!(#name: obj.#index as _)
});
let id: TokenStream = c.id.parse().unwrap();
quote!({ let obj = #f; #id { #(#fields),*} })
}
(Type::Struct { ref fields, .. }, Type::Struct { name: Some(n), .. }) => {
let fields = fields.iter().enumerate().map(|(index, (name, _))| {
let index = proc_macro2::Literal::usize_unsuffixed(index);

View file

@ -23,9 +23,6 @@ pub enum Type {
InferredProperty,
/// The type of a callback alias whose type was not yet inferred
InferredCallback,
Component(Rc<Component>),
Builtin(Rc<BuiltinElement>),
Native(Rc<NativeClass>),
Callback {
return_type: Option<Box<Type>>,
@ -82,9 +79,6 @@ impl core::cmp::PartialEq for Type {
Type::Void => matches!(other, Type::Void),
Type::InferredProperty => matches!(other, Type::InferredProperty),
Type::InferredCallback => matches!(other, Type::InferredCallback),
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::Callback { args: a, return_type: ra } => {
matches!(other, Type::Callback { args: b, return_type: rb } if a == b && ra == rb)
}
@ -125,9 +119,6 @@ impl Display for Type {
Type::Void => write!(f, "void"),
Type::InferredProperty => write!(f, "?"),
Type::InferredCallback => write!(f, "callback"),
Type::Component(c) => c.id.fmt(f),
Type::Builtin(b) => b.name.fmt(f),
Type::Native(b) => b.class_name.fmt(f),
Type::Callback { args, return_type } => {
write!(f, "callback")?;
if !args.is_empty() {
@ -234,168 +225,6 @@ impl Type {
!matches!(self, Self::Easing)
}
pub fn lookup_property<'a>(&self, name: &'a str) -> PropertyLookupResult<'a> {
match self {
Type::Component(c) => c.root_element.borrow().lookup_property(name),
Type::Builtin(b) => {
let resolved_name =
if let Some(alias_name) = b.native_class.lookup_alias(name.as_ref()) {
Cow::Owned(alias_name.to_string())
} else {
Cow::Borrowed(name)
};
match b.properties.get(resolved_name.as_ref()) {
None => {
if b.is_non_item_type {
PropertyLookupResult {
resolved_name,
property_type: Type::Invalid,
property_visibility: PropertyVisibility::Private,
is_local_to_component: false,
}
} else {
crate::typeregister::reserved_property(name)
}
}
Some(p) => PropertyLookupResult {
resolved_name,
property_type: p.ty.clone(),
property_visibility: PropertyVisibility::InOut,
is_local_to_component: false,
},
}
}
Type::Native(n) => {
let resolved_name = if let Some(alias_name) = n.lookup_alias(name.as_ref()) {
Cow::Owned(alias_name.to_string())
} else {
Cow::Borrowed(name)
};
let property_type =
n.lookup_property(resolved_name.as_ref()).cloned().unwrap_or_default();
PropertyLookupResult {
resolved_name,
property_type,
property_visibility: PropertyVisibility::InOut,
is_local_to_component: false,
}
}
_ => PropertyLookupResult {
resolved_name: Cow::Borrowed(name),
property_type: Type::Invalid,
property_visibility: PropertyVisibility::Private,
is_local_to_component: false,
},
}
}
/// List of sub properties valid for the auto completion
pub fn property_list(&self) -> Vec<(String, Type)> {
match self {
Type::Component(c) => {
let mut r = c.root_element.borrow().base_type.property_list();
r.extend(
c.root_element
.borrow()
.property_declarations
.iter()
.map(|(k, d)| (k.clone(), d.property_type.clone())),
);
r
}
Type::Builtin(b) => {
b.properties.iter().map(|(k, t)| (k.clone(), t.ty.clone())).collect()
}
Type::Native(n) => {
n.properties.iter().map(|(k, t)| (k.clone(), t.ty.clone())).collect()
}
_ => Vec::new(),
}
}
pub fn lookup_type_for_child_element(
&self,
name: &str,
tr: &TypeRegister,
) -> Result<Type, String> {
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).and_then(|t| {
if !tr.expose_internal_types && matches!(&t, Type::Builtin(e) if e.is_internal) {
Err(format!("Unknown type {}. (The type exist as an internal type, but cannot be accessed in this scope)", name))
} else {
Ok(t)
}
})
}
pub fn lookup_member_function(&self, name: &str) -> Expression {
match self {
Type::Builtin(builtin) => builtin
.member_functions
.get(name)
.cloned()
.unwrap_or_else(|| crate::typeregister::reserved_member_function(name)),
Type::Component(component) => {
component.root_element.borrow().base_type.lookup_member_function(name)
}
_ => 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"),
}
}
/// Assume it is a Component, panic if it isn't
pub fn as_component(&self) -> &Rc<Component> {
match self {
Type::Component(c) => c,
_ => panic!("should be a component because of the repeater_component pass"),
}
}
/// Assume it is an enumeration, panic if it isn't
pub fn as_enum(&self) -> &Rc<Enumeration> {
match self {
@ -455,26 +284,6 @@ impl Type {
}
}
pub fn collect_contextual_types(
&self,
context_restricted_types: &mut HashMap<String, HashSet<String>>,
) {
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<Unit> {
@ -488,9 +297,6 @@ impl Type {
Type::Invalid => None,
Type::Void => None,
Type::InferredProperty | Type::InferredCallback => None,
Type::Component(_) => None,
Type::Builtin(_) => None,
Type::Native(_) => None,
Type::Callback { .. } => None,
Type::Function { .. } => None,
Type::Float32 => None,
@ -548,6 +354,240 @@ impl BuiltinPropertyInfo {
}
}
/// The base of an element
#[derive(Clone, Debug)]
pub enum ElementType {
/// The element is based of a component
Component(Rc<Component>),
/// The element is a builtin element
Builtin(Rc<BuiltinElement>),
/// The native type was resolved by the resolve_native_class pass.
Native(Rc<NativeClass>),
/// The base element couldn't be looked up
Error,
/// This should be the base type of the root element of a global component
Global,
}
impl PartialEq for ElementType {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Component(a), Self::Component(b)) => Rc::ptr_eq(a, b),
(Self::Builtin(a), Self::Builtin(b)) => Rc::ptr_eq(a, b),
(Self::Native(a), Self::Native(b)) => Rc::ptr_eq(a, b),
(Self::Error, Self::Error) | (Self::Global, Self::Global) => true,
_ => false,
}
}
}
impl ElementType {
pub fn lookup_property<'a>(&self, name: &'a str) -> PropertyLookupResult<'a> {
match self {
Self::Component(c) => c.root_element.borrow().lookup_property(name),
Self::Builtin(b) => {
let resolved_name =
if let Some(alias_name) = b.native_class.lookup_alias(name.as_ref()) {
Cow::Owned(alias_name.to_string())
} else {
Cow::Borrowed(name)
};
match b.properties.get(resolved_name.as_ref()) {
None => {
if b.is_non_item_type {
PropertyLookupResult {
resolved_name,
property_type: Type::Invalid,
property_visibility: PropertyVisibility::Private,
is_local_to_component: false,
}
} else {
crate::typeregister::reserved_property(name)
}
}
Some(p) => PropertyLookupResult {
resolved_name,
property_type: p.ty.clone(),
property_visibility: PropertyVisibility::InOut,
is_local_to_component: false,
},
}
}
Self::Native(n) => {
let resolved_name = if let Some(alias_name) = n.lookup_alias(name.as_ref()) {
Cow::Owned(alias_name.to_string())
} else {
Cow::Borrowed(name)
};
let property_type =
n.lookup_property(resolved_name.as_ref()).cloned().unwrap_or_default();
PropertyLookupResult {
resolved_name,
property_type,
property_visibility: PropertyVisibility::InOut,
is_local_to_component: false,
}
}
_ => PropertyLookupResult {
resolved_name: Cow::Borrowed(name),
property_type: Type::Invalid,
property_visibility: PropertyVisibility::Private,
is_local_to_component: false,
},
}
}
/// List of sub properties valid for the auto completion
pub fn property_list(&self) -> Vec<(String, Type)> {
match self {
Self::Component(c) => {
let mut r = c.root_element.borrow().base_type.property_list();
r.extend(
c.root_element
.borrow()
.property_declarations
.iter()
.map(|(k, d)| (k.clone(), d.property_type.clone())),
);
r
}
Self::Builtin(b) => {
b.properties.iter().map(|(k, t)| (k.clone(), t.ty.clone())).collect()
}
Self::Native(n) => {
n.properties.iter().map(|(k, t)| (k.clone(), t.ty.clone())).collect()
}
_ => Vec::new(),
}
}
pub fn lookup_type_for_child_element(
&self,
name: &str,
tr: &TypeRegister,
) -> Result<ElementType, String> {
match self {
Self::Component(component) => {
return component
.root_element
.borrow()
.base_type
.lookup_type_for_child_element(name, tr)
}
Self::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).and_then(|t| {
if !tr.expose_internal_types && matches!(&t, Self::Builtin(e) if e.is_internal) {
Err(format!("Unknown type {}. (The type exist as an internal type, but cannot be accessed in this scope)", name))
} else {
Ok(t)
}
}).map_err(|s| {
match tr.lookup(name) {
Type::Invalid => s,
ty => format!("'{ty}' cannot be used as an element")
}
})
}
pub fn lookup_member_function(&self, name: &str) -> Expression {
match self {
Self::Builtin(builtin) => builtin
.member_functions
.get(name)
.cloned()
.unwrap_or_else(|| crate::typeregister::reserved_member_function(name)),
Self::Component(component) => {
component.root_element.borrow().base_type.lookup_member_function(name)
}
_ => Expression::Invalid,
}
}
pub fn collect_contextual_types(
&self,
context_restricted_types: &mut HashMap<String, HashSet<String>>,
) {
let builtin = match self {
Self::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);
}
}
/// Assume this is a builtin type, panic if it isn't
pub fn as_builtin(&self) -> &BuiltinElement {
match self {
Self::Builtin(b) => b,
Self::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 {
Self::Native(b) => b,
Self::Component(_) => {
panic!("This should not happen because of native class resolution")
}
_ => panic!("invalid type"),
}
}
/// Assume it is a Component, panic if it isn't
pub fn as_component(&self) -> &Rc<Component> {
match self {
Self::Component(c) => c,
_ => panic!("should be a component because of the repeater_component pass"),
}
}
}
impl Display for ElementType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Component(c) => c.id.fmt(f),
Self::Builtin(b) => b.name.fmt(f),
Self::Native(b) => b.class_name.fmt(f),
Self::Error => write!(f, "<error>"),
Self::Global => Ok(()),
}
}
}
impl Default for ElementType {
fn default() -> Self {
Self::Error
}
}
#[derive(Debug, Clone, Default)]
pub struct NativeClass {
pub parent: Option<Rc<NativeClass>>,
@ -627,7 +667,7 @@ pub struct BuiltinElement {
pub name: String,
pub native_class: Rc<NativeClass>,
pub properties: BTreeMap<String, BuiltinPropertyInfo>,
pub additional_accepted_child_types: HashMap<String, Type>,
pub additional_accepted_child_types: HashMap<String, ElementType>,
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,

View file

@ -5,7 +5,7 @@
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::*;
use crate::langtype::{PropertyLookupResult, Type};
use crate::langtype::{ElementType, PropertyLookupResult, Type};
use crate::object_tree::{Component, ElementRc};
use std::cell::RefCell;
@ -377,7 +377,7 @@ fn find_binding<R>(
return Some(f(&b.borrow(), &element.borrow().enclosing_component, depth));
}
let e = match &element.borrow().base_type {
Type::Component(base) => base.root_element.clone(),
ElementType::Component(base) => base.root_element.clone(),
_ => return None,
};
element = e;
@ -489,7 +489,7 @@ pub fn implicit_layout_info_call(elem: &ElementRc, orientation: Orientation) ->
let mut elem_it = elem.clone();
loop {
return match &elem_it.clone().borrow().base_type {
Type::Component(base_comp) => {
ElementType::Component(base_comp) => {
match base_comp.root_element.borrow().layout_info_prop(orientation) {
Some(nr) => {
// We cannot take nr as is because it is relative to the elem's component. We therefore need to
@ -503,7 +503,7 @@ pub fn implicit_layout_info_call(elem: &ElementRc, orientation: Orientation) ->
}
}
}
Type::Builtin(base_type) if base_type.name == "Rectangle" => {
ElementType::Builtin(base_type) if base_type.name == "Rectangle" => {
// hard-code the value for rectangle because many rectangle end up optimized away and we
// don't want to depend on the element.
Expression::Struct {

View file

@ -182,9 +182,6 @@ impl Expression {
pub fn default_value_for_type(ty: &Type) -> Option<Self> {
Some(match ty {
Type::Invalid
| Type::Component(_)
| Type::Builtin(_)
| Type::Native(_)
| Type::Callback { .. }
| Type::Function { .. }
| Type::Void

View file

@ -4,7 +4,7 @@
use by_address::ByAddress;
use crate::expression_tree::Expression as tree_Expression;
use crate::langtype::Type;
use crate::langtype::{ElementType, Type};
use crate::llr::item_tree::*;
use crate::namedreference::NamedReference;
use crate::object_tree::{Component, ElementRc};
@ -93,7 +93,7 @@ impl LoweredSubComponentMapping {
}
match self.element_mapping.get(&element.clone().into()).unwrap() {
LoweredElement::SubComponent { sub_component_index } => {
if let Type::Component(base) = &element.borrow().base_type {
if let ElementType::Component(base) = &element.borrow().base_type {
return property_reference_within_sub_component(
state.map_property_reference(&NamedReference::new(
&base.root_element,
@ -245,7 +245,7 @@ fn lower_sub_component(
return None;
}
match &elem.base_type {
Type::Component(comp) => {
ElementType::Component(comp) => {
let lc = state.sub_component(comp);
let ty = lc.sub_component.clone();
let sub_component_index = sub_component.sub_components.len();
@ -263,7 +263,7 @@ fn lower_sub_component(
repeater_offset += ty.repeater_count();
}
Type::Native(n) => {
ElementType::Native(n) => {
let item_index = sub_component.items.len();
mapping
.element_mapping
@ -422,12 +422,12 @@ fn get_property_analysis(elem: &ElementRc, p: &str) -> crate::object_tree::Prope
loop {
let base = elem.borrow().base_type.clone();
match base {
Type::Native(n) => {
ElementType::Native(n) => {
if n.properties.get(p).map_or(false, |p| p.is_native_output) {
a.is_set = true;
}
}
Type::Component(c) => {
ElementType::Component(c) => {
elem = c.root_element.clone();
if let Some(a2) = elem.borrow().property_analysis.borrow().get(p) {
a.merge_with_base(a2);

View file

@ -10,7 +10,9 @@ use std::collections::HashMap;
use std::rc::Rc;
use crate::expression_tree::Expression;
use crate::langtype::{BuiltinElement, BuiltinPropertyInfo, DefaultSizeBinding, NativeClass, Type};
use crate::langtype::{
BuiltinElement, BuiltinPropertyInfo, DefaultSizeBinding, ElementType, NativeClass, Type,
};
use crate::object_tree::{self, *};
use crate::parser::{identifier_text, syntax_nodes, SyntaxKind, SyntaxNode};
use crate::typeregister::TypeRegister;
@ -178,25 +180,24 @@ pub fn load_builtins(register: &mut TypeRegister) {
.map(|s| {
let a = identifier_text(&s.Element().QualifiedName().unwrap()).unwrap();
let t = natives[&a].clone();
(a, Type::Builtin(t))
(a, ElementType::Builtin(t))
})
.collect();
if let Some(builtin_name) = exports.get(&id) {
if !matches!(&base, Base::Global) {
builtin.name = builtin_name.clone();
register
.insert_type_with_name(Type::Builtin(Rc::new(builtin)), builtin_name.clone());
register.add_builtin(Rc::new(builtin));
} else {
let glob = Rc::new(Component {
id: builtin_name.clone(),
root_element: Rc::new(RefCell::new(Element {
base_type: Type::Builtin(Rc::new(builtin)),
base_type: ElementType::Builtin(Rc::new(builtin)),
..Default::default()
})),
..Default::default()
});
glob.root_element.borrow_mut().enclosing_component = Rc::downgrade(&glob);
register.insert_type(Type::Component(glob));
register.add(glob);
}
} else {
// because they are not taken from if we inherit from it
@ -205,7 +206,8 @@ pub fn load_builtins(register: &mut TypeRegister) {
}
}
register.property_animation_type = Type::Builtin(natives.remove("PropertyAnimation").unwrap());
register.property_animation_type =
ElementType::Builtin(natives.remove("PropertyAnimation").unwrap());
if !diag.is_empty() {
let vec = diag.to_string_vec();

View file

@ -9,7 +9,7 @@ use crate::diagnostics::{BuildDiagnostics, Spanned};
use crate::expression_tree::{
BuiltinFunction, BuiltinMacroFunction, EasingCurve, Expression, Unit,
};
use crate::langtype::{Enumeration, EnumerationValue, Type};
use crate::langtype::{ElementType, Enumeration, EnumerationValue, Type};
use crate::namedreference::NamedReference;
use crate::object_tree::{ElementRc, PropertyVisibility};
use crate::parser::NodeOrToken;
@ -422,7 +422,12 @@ impl LookupObject for LookupType {
f: &mut impl FnMut(&str, LookupResult) -> Option<R>,
) -> Option<R> {
for (name, ty) in ctx.type_register.all_types() {
if let Some(r) = Self::as_result(ty).and_then(|e| f(&name, e)) {
if let Some(r) = Self::from_type(ty).and_then(|e| f(&name, e)) {
return Some(r);
}
}
for (name, ty) in ctx.type_register.all_elements() {
if let Some(r) = Self::from_element(ty).and_then(|e| f(&name, e)) {
return Some(r);
}
}
@ -430,16 +435,23 @@ impl LookupObject for LookupType {
}
fn lookup(&self, ctx: &LookupCtx, name: &str) -> Option<LookupResult> {
Self::as_result(ctx.type_register.lookup(name)).map(LookupResult::from)
Self::from_type(ctx.type_register.lookup(name))
.or_else(|| Self::from_element(ctx.type_register.lookup_element(name).ok()?))
}
}
impl LookupType {
fn as_result(ty: Type) -> Option<LookupResult> {
fn from_type(ty: Type) -> Option<LookupResult> {
match ty {
Type::Component(c) if c.is_global() => {
Type::Enumeration(e) => Some(LookupResult::Enumeration(e)),
_ => None,
}
}
fn from_element(el: ElementType) -> Option<LookupResult> {
match el {
ElementType::Component(c) if c.is_global() => {
Some(Expression::ElementReference(Rc::downgrade(&c.root_element)).into())
}
Type::Enumeration(e) => Some(LookupResult::Enumeration(e)),
_ => None,
}
}
@ -730,7 +742,6 @@ impl LookupObject for Expression {
}
None
}
Type::Component(c) => c.root_element.for_each_entry(ctx, f),
Type::String => StringExpression(self).for_each_entry(ctx, f),
Type::Brush | Type::Color => ColorExpression(self).for_each_entry(ctx, f),
Type::Image => ImageExpression(self).for_each_entry(ctx, f),
@ -750,7 +761,6 @@ impl LookupObject for Expression {
name: name.to_string(),
})
}),
Type::Component(c) => c.root_element.lookup(ctx, name),
Type::String => StringExpression(self).lookup(ctx, name),
Type::Brush | Type::Color => ColorExpression(self).lookup(ctx, name),
Type::Image => ImageExpression(self).lookup(ctx, name),

View file

@ -10,7 +10,7 @@ use std::collections::HashMap;
use std::hash::Hash;
use std::rc::{Rc, Weak};
use crate::langtype::Type;
use crate::langtype::{ElementType, Type};
use crate::object_tree::{Element, ElementRc, PropertyAnalysis};
/// Reference to a property or callback of a given name within an element.
@ -98,19 +98,21 @@ impl NamedReference {
return true;
}
match &e.base_type {
Type::Component(c) => {
ElementType::Component(c) => {
let next = c.root_element.clone();
drop(e);
elem = next;
continue;
}
Type::Builtin(b) => {
ElementType::Builtin(b) => {
return b.properties.get(self.name()).map_or(true, |pi| !pi.is_native_output)
}
Type::Native(n) => {
ElementType::Native(n) => {
return n.properties.get(self.name()).map_or(true, |pi| !pi.is_native_output)
}
_ => return true,
crate::langtype::ElementType::Error | crate::langtype::ElementType::Global => {
return true
}
}
}
}
@ -195,7 +197,7 @@ impl NamedReferenceContainer {
/// Mark that a given property is `is_set_externally` in all bases
pub(crate) fn mark_property_set_derived_in_base(mut element: ElementRc, name: &str) {
loop {
let next = if let Type::Component(c) = &element.borrow().base_type {
let next = if let ElementType::Component(c) = &element.borrow().base_type {
if element.borrow().property_declarations.contains_key(name) {
return;
};

View file

@ -11,8 +11,8 @@ use itertools::Either;
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
use crate::expression_tree::{self, BindingExpression, Expression, Unit};
use crate::langtype::PropertyLookupResult;
use crate::langtype::{BuiltinElement, NativeClass, Type};
use crate::langtype::{ElementType, PropertyLookupResult};
use crate::layout::{LayoutConstraints, Orientation};
use crate::namedreference::NamedReference;
use crate::parser;
@ -22,6 +22,7 @@ use crate::typeregister::TypeRegister;
use std::cell::{Cell, RefCell};
use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, HashMap};
use std::fmt::Display;
use std::rc::{Rc, Weak};
macro_rules! unwrap_or_continue {
@ -120,8 +121,9 @@ impl Document {
crate::typeloader::ImportedName::extract_imported_names(&import)
.and_then(|it| it.last())
})
.and_then(|import| match local_registry.lookup(&import.internal_name) {
Type::Component(c) => Some(c),
.and_then(|import| local_registry.lookup_element(&import.internal_name).ok())
.and_then(|c| match c {
ElementType::Component(c) => Some(c),
_ => None,
})
})
@ -169,10 +171,6 @@ impl Document {
exports,
}
}
pub fn exports(&self) -> &Vec<(ExportedName, Type)> {
&self.exports.0
}
}
#[derive(Debug, Clone)]
@ -256,7 +254,7 @@ impl Component {
root_element: Element::from_node(
node.Element(),
"root".into(),
Type::Invalid,
ElementType::Error,
&mut child_insertion_point,
diag,
tr,
@ -276,18 +274,12 @@ impl Component {
/// This component is a global component introduced with the "global" keyword
pub fn is_global(&self) -> bool {
match &self.root_element.borrow().base_type {
Type::Void => true,
Type::Builtin(c) => c.is_global,
ElementType::Global => true,
ElementType::Builtin(c) => c.is_global,
_ => false,
}
}
/// Returns true if use/instantiation of this component requires generating
/// code in Rust/C++/etc..
pub fn requires_code_generation(&self) -> bool {
!matches!(self.root_element.borrow().base_type, Type::Builtin(_))
}
pub fn visible_in_public_api(&self) -> bool {
if self.is_global() {
!self.exported_global_names.borrow().is_empty()
@ -342,7 +334,7 @@ impl Default for PropertyVisibility {
}
}
impl std::fmt::Display for PropertyVisibility {
impl Display for PropertyVisibility {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PropertyVisibility::Private => f.write_str("private"),
@ -466,7 +458,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::langtype::Type,
pub base_type: ElementType,
/// Currently contains also the callbacks. FIXME: should that be changed?
pub bindings: BindingsMap,
pub property_analysis: RefCell<HashMap<String, PropertyAnalysis>>,
@ -667,7 +659,7 @@ impl Element {
pub fn from_node(
node: syntax_nodes::Element,
id: String,
parent_type: Type,
parent_type: ElementType,
component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
diag: &mut BuildDiagnostics,
tr: &TypeRegister,
@ -676,25 +668,21 @@ impl Element {
let base = QualifiedTypeName::from_node(base_node.clone());
let base_string = base.to_string();
match parent_type.lookup_type_for_child_element(&base_string, tr) {
Ok(Type::Component(c)) if c.is_global() => {
Ok(ElementType::Component(c)) if c.is_global() => {
diag.push_error(
"Cannot create an instance of a global component".into(),
&base_node,
);
Type::Invalid
}
Ok(ty @ Type::Component(_)) | Ok(ty @ Type::Builtin(_)) => ty,
Ok(ty) => {
diag.push_error(format!("'{}' cannot be used as an element", ty), &base_node);
Type::Invalid
ElementType::Error
}
Ok(ty) => ty,
Err(err) => {
diag.push_error(err, &base_node);
Type::Invalid
ElementType::Error
}
}
} else {
if parent_type != Type::Invalid {
if parent_type != ElementType::Error {
// This should normally never happen because the parser does not allow for this
assert!(diag.has_error());
return ElementRc::default();
@ -712,7 +700,7 @@ impl Element {
node.PropertyAnimation().for_each(|n| error_on(&n, "animations"));
node.States().for_each(|n| error_on(&n, "states"));
node.Transitions().for_each(|n| error_on(&n, "transitions"));
Type::Void
ElementType::Global
};
let mut r = Element { id, base_type, node: Some(node.clone()), ..Default::default() };
@ -1045,7 +1033,7 @@ impl Element {
fn from_sub_element_node(
node: syntax_nodes::SubElement,
parent_type: Type,
parent_type: ElementType,
component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
diag: &mut BuildDiagnostics,
tr: &TypeRegister,
@ -1111,7 +1099,7 @@ impl Element {
fn from_conditional_node(
node: syntax_nodes::ConditionalElement,
parent_type: Type,
parent_type: ElementType,
component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
diag: &mut BuildDiagnostics,
tr: &TypeRegister,
@ -1169,7 +1157,7 @@ impl Element {
if !lookup_result.property_type.is_property_type() {
match lookup_result.property_type {
Type::Invalid => {
if self.base_type != Type::Invalid {
if self.base_type != ElementType::Error {
diag.push_error(format!(
"Unknown property {} in {}",
unresolved_name, self.base_type
@ -1225,11 +1213,11 @@ impl Element {
let mut base_type = self.base_type.clone();
loop {
match &base_type {
Type::Component(component) => {
ElementType::Component(component) => {
base_type = component.root_element.clone().borrow().base_type.clone();
}
Type::Builtin(builtin) => break Some(builtin.native_class.clone()),
Type::Native(native) => break Some(native.clone()),
ElementType::Builtin(builtin) => break Some(builtin.native_class.clone()),
ElementType::Native(native) => break Some(native.clone()),
_ => break None,
}
}
@ -1239,10 +1227,10 @@ impl Element {
let mut base_type = self.base_type.clone();
loop {
match &base_type {
Type::Component(component) => {
ElementType::Component(component) => {
base_type = component.root_element.clone().borrow().base_type.clone();
}
Type::Builtin(builtin) => break Some(builtin.clone()),
ElementType::Builtin(builtin) => break Some(builtin.clone()),
_ => break None,
}
}
@ -1273,7 +1261,7 @@ impl Element {
b.borrow().has_binding() && (!need_explicit || b.borrow().priority > 0)
}) {
true
} else if let Type::Component(base) = &self.base_type {
} else if let ElementType::Component(base) = &self.base_type {
base.root_element.borrow().is_binding_set(property_name, need_explicit)
} else {
false
@ -1308,7 +1296,7 @@ impl Element {
pub fn sub_component(&self) -> Option<&Rc<Component>> {
if self.repeated.is_some() {
None
} else if let Type::Component(sub_component) = &self.base_type {
} else if let ElementType::Component(sub_component) = &self.base_type {
Some(sub_component)
} else {
None
@ -1319,7 +1307,7 @@ impl Element {
/// Apply default property values defined in `builtins.slint` to the element.
fn apply_default_type_properties(element: &mut Element) {
// Apply default property values on top:
if let Type::Builtin(builtin_base) = &element.base_type {
if let ElementType::Builtin(builtin_base) = &element.base_type {
for (prop, info) in &builtin_base.properties {
if let Some(expr) = &info.default_value {
element.bindings.entry(prop.clone()).or_insert_with(|| {
@ -1343,10 +1331,13 @@ pub fn type_from_node(
let prop_type = tr.lookup_qualified(&qualified_type.members);
if prop_type == Type::Invalid {
if prop_type == Type::Invalid && tr.lookup_element(&qualified_type.to_string()).is_err() {
diag.push_error(format!("Unknown type '{}'", qualified_type), &qualified_type_node);
} else if !prop_type.is_property_type() {
diag.push_error(format!("'{}' is not a valid type", prop_type), &qualified_type_node);
diag.push_error(
format!("'{}' is not a valid type", qualified_type),
&qualified_type_node,
);
}
prop_type
} else if let Some(object_node) = node.ObjectType() {
@ -1385,7 +1376,7 @@ fn animation_element_from_node(
tr: &TypeRegister,
) -> Option<ElementRc> {
let anim_type = tr.property_animation_type_for_property(prop_type);
if !matches!(anim_type, Type::Builtin(..)) {
if !matches!(anim_type, ElementType::Builtin(..)) {
diag.push_error(
format!(
"'{}' is not a property that can be animated",
@ -1427,7 +1418,7 @@ impl QualifiedTypeName {
}
}
impl std::fmt::Display for QualifiedTypeName {
impl Display for QualifiedTypeName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.members.join("."))
}
@ -1558,7 +1549,7 @@ pub fn recurse_elem_including_sub_components<State>(
(&*elem.borrow().enclosing_component.upgrade().unwrap()) as *const Component
));
if elem.borrow().repeated.is_some() {
if let Type::Component(base) = &elem.borrow().base_type {
if let ElementType::Component(base) = &elem.borrow().base_type {
if base.parent_element.upgrade().is_some() {
recurse_elem_including_sub_components(base, state, vis);
}
@ -1594,7 +1585,7 @@ pub fn recurse_elem_including_sub_components_no_borrow<State>(
) {
recurse_elem_no_borrow(&component.root_element, state, &mut |elem, state| {
let base = if elem.borrow().repeated.is_some() {
if let Type::Component(base) = &elem.borrow().base_type {
if let ElementType::Component(base) = &elem.borrow().base_type {
Some(base.clone())
} else {
None
@ -1824,7 +1815,7 @@ impl ExportedName {
}
#[derive(Default, Debug, derive_more::Deref)]
pub struct Exports(pub Vec<(ExportedName, Type)>);
pub struct Exports(pub Vec<(ExportedName, Either<Rc<Component>, Type>)>);
impl Exports {
pub fn from_node(
@ -1945,27 +1936,34 @@ impl Exports {
}
}
let mut resolve_export_to_inner_component_or_import =
|export: &NamedExport| match type_registry.lookup(export.internal_name.as_str()) {
ty @ Type::Component(_) | ty @ Type::Struct { .. } => Some(ty),
Type::Invalid => {
diag.push_error(
format!("'{}' not found", export.internal_name),
&export.internal_name_ident,
);
None
}
_ => {
diag.push_error(
format!(
"Cannot export '{}' because it is not a component",
export.internal_name,
),
&export.internal_name_ident,
);
None
}
};
let mut resolve_export_to_inner_component_or_import = |export: &NamedExport| {
if let Ok(ElementType::Component(c)) =
type_registry.lookup_element(export.internal_name.as_str())
{
Some(Either::Left(c))
} else if let ty @ Type::Struct { .. } =
type_registry.lookup(export.internal_name.as_str())
{
Some(Either::Right(ty))
} else if type_registry.lookup_element(export.internal_name.as_str()).is_ok()
|| type_registry.lookup(export.internal_name.as_str()) != Type::Invalid
{
diag.push_error(
format!(
"Cannot export '{}' because it is not a component",
export.internal_name,
),
&export.internal_name_ident,
);
None
} else {
diag.push_error(
format!("'{}' not found", export.internal_name,),
&export.internal_name_ident,
);
None
}
};
Self(
exports
@ -2026,7 +2024,7 @@ pub fn inject_element_as_repeated_element(repeated_element: &ElementRc, new_root
new_root.borrow_mut().children.push(old_root);
let component = Rc::new(component);
repeated_element.borrow_mut().base_type = Type::Component(component.clone());
repeated_element.borrow_mut().base_type = ElementType::Component(component.clone());
for elem in elements_with_enclosing_component_reference {
elem.borrow_mut().enclosing_component = Rc::downgrade(&component);

View file

@ -44,7 +44,7 @@ mod visible;
mod z_order;
use crate::expression_tree::Expression;
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::namedreference::NamedReference;
use std::collections::HashSet;
use std::rc::Rc;
@ -55,7 +55,10 @@ pub async fn run_passes(
type_loader: &mut crate::typeloader::TypeLoader,
compiler_config: &crate::CompilerConfiguration,
) {
if matches!(doc.root_component.root_element.borrow().base_type, Type::Invalid | Type::Void) {
if matches!(
doc.root_component.root_element.borrow().base_type,
ElementType::Error | ElementType::Global
) {
// If there isn't a root component, we shouldn't do any of these passes
return;
}
@ -63,14 +66,10 @@ pub async fn run_passes(
let style_metrics = {
// Ignore import errors
let mut build_diags_to_ignore = crate::diagnostics::BuildDiagnostics::default();
let style_metrics = type_loader
.import_type("std-widgets.slint", "StyleMetrics", &mut build_diags_to_ignore)
.await;
if let Some(Type::Component(c)) = style_metrics {
c
} else {
panic!("can't load style metrics")
}
type_loader
.import_component("std-widgets.slint", "StyleMetrics", &mut build_diags_to_ignore)
.await
.unwrap_or_else(|| panic!("can't load style metrics"))
};
let global_type_registry = type_loader.global_type_registry.clone();

View file

@ -14,7 +14,8 @@ use crate::diagnostics::Spanned;
use crate::expression_tree::BindingExpression;
use crate::expression_tree::BuiltinFunction;
use crate::expression_tree::Expression;
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::layout::LayoutItem;
use crate::layout::Orientation;
use crate::namedreference::NamedReference;
@ -309,7 +310,7 @@ fn process_property(
if element.borrow().bindings.contains_key(prop.prop.name()) {
analyse_binding(&prop, context, reverse_aliases, diag);
}
let next = if let Type::Component(base) = &element.borrow().base_type {
let next = if let ElementType::Component(base) = &element.borrow().base_type {
if element.borrow().property_declarations.contains_key(prop.prop.name()) {
break;
}
@ -397,7 +398,7 @@ fn visit_layout_items_dependencies<'a>(
if let Some(nr) = element.borrow().layout_info_prop(orientation) {
vis(&nr.clone().into());
} else {
if let Type::Component(base) = &element.borrow().base_type {
if let ElementType::Component(base) = &element.borrow().base_type {
if let Some(nr) = base.root_element.borrow().layout_info_prop(orientation) {
vis(&PropertyPath {
elements: vec![ByAddress(element.clone())],
@ -543,7 +544,7 @@ fn mark_used_base_properties(component: &Rc<Component>) {
component,
&(),
&mut |element, _| {
if !matches!(element.borrow().base_type, Type::Component(_)) {
if !matches!(element.borrow().base_type, ElementType::Component(_)) {
return;
}
for (name, binding) in &element.borrow().bindings {

View file

@ -5,13 +5,13 @@
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::Expression;
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::object_tree::{Component, ElementRc};
use std::rc::Rc;
pub fn check_aliases(component: &Rc<Component>, diag: &mut BuildDiagnostics) {
crate::object_tree::recurse_elem_including_sub_components(&component, &(), &mut |elem, _| {
let base = if let Type::Component(base) = &elem.borrow().base_type {
let base = if let ElementType::Component(base) = &elem.borrow().base_type {
base.clone()
} else {
return;
@ -54,7 +54,7 @@ fn explicit_binding_priority(elem: &ElementRc, name: &str) -> Option<i32> {
}
None
}
} else if let Type::Component(base) = &elem.borrow().base_type {
} else if let ElementType::Component(base) = &elem.borrow().base_type {
explicit_binding_priority(&base.root_element, name).map(|p| p.saturating_add(1))
} else {
None

View file

@ -6,13 +6,12 @@
use std::rc::Rc;
use crate::diagnostics::{BuildDiagnostics, DiagnosticLevel};
use crate::langtype::Type;
use crate::object_tree::{Component, Document};
pub fn check_public_api(doc: &Document, diag: &mut BuildDiagnostics) {
check_public_api_component(&doc.root_component, diag);
for (export_name, ty) in doc.exports() {
if let Type::Component(c) = ty {
for (export_name, e) in &doc.exports.0 {
if let Some(c) = e.as_ref().left() {
if c.is_global() {
// This global will become part of the public API.
c.exported_global_names.borrow_mut().push(export_name.clone());

View file

@ -3,7 +3,7 @@
use crate::diagnostics::BuildDiagnostics;
use crate::diagnostics::Spanned;
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::object_tree::Element;
/// Check that the rotation is only on Image
@ -40,12 +40,12 @@ pub fn check_rotation(doc: &crate::object_tree::Document, diag: &mut BuildDiagno
/// Returns true if this element or its base have any children.
fn has_any_children(e: &Element) -> bool {
!e.children.is_empty()
|| matches!(&e.base_type, Type::Component(base) if has_any_children(&base.root_element.borrow()))
|| matches!(&e.base_type, ElementType::Component(base) if has_any_children(&base.root_element.borrow()))
}
/// Returns true if the property is set.
fn is_property_set(e: &Element, property_name: &str) -> bool {
e.bindings.contains_key(property_name)
|| e.property_analysis.borrow().get(property_name).map_or(false, |a| a.is_set)
|| matches!(&e.base_type, Type::Component(base) if is_property_set(&base.root_element.borrow(), property_name))
|| matches!(&e.base_type, ElementType::Component(base) if is_property_set(&base.root_element.borrow(), property_name))
}

View file

@ -8,7 +8,7 @@ use std::rc::Rc;
use crate::diagnostics::{BuildDiagnostics, Spanned};
use crate::expression_tree::{BindingExpression, Expression, NamedReference};
use crate::langtype::{NativeClass, Type};
use crate::langtype::NativeClass;
use crate::object_tree::{Component, Element, ElementRc};
use crate::typeregister::TypeRegister;
@ -17,7 +17,8 @@ pub fn handle_clip(
type_register: &TypeRegister,
diag: &mut BuildDiagnostics,
) {
let native_clip = type_register.lookup("Clip").as_builtin().native_class.clone();
let native_clip =
type_register.lookup_element("Clip").unwrap().as_builtin().native_class.clone();
crate::object_tree::recurse_elem_including_sub_components(
component,
@ -55,7 +56,7 @@ fn create_clip_element(parent_elem: &ElementRc, native_clip: &Rc<NativeClass>) {
let mut parent = parent_elem.borrow_mut();
let clip = Rc::new(RefCell::new(Element {
id: format!("{}-clip", parent.id),
base_type: Type::Native(native_clip.clone()),
base_type: crate::langtype::ElementType::Native(native_clip.clone()),
children: std::mem::take(&mut parent.children),
enclosing_component: parent.enclosing_component.clone(),
..Element::default()

View file

@ -7,7 +7,6 @@ use by_address::ByAddress;
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::NamedReference;
use crate::langtype::Type;
use crate::object_tree::*;
use std::collections::HashSet;
use std::rc::Rc;
@ -17,8 +16,8 @@ pub fn collect_globals(doc: &Document, _diag: &mut BuildDiagnostics) {
doc.root_component.used_types.borrow_mut().globals.clear();
let mut set = HashSet::new();
let mut sorted_globals = vec![];
for (_, ty) in doc.exports() {
if let Type::Component(c) = ty {
for (_, ty) in &doc.exports.0 {
if let Some(c) = ty.as_ref().left() {
if c.is_global() {
if set.insert(ByAddress(c.clone())) {
collect_in_component(c, &mut set, &mut sorted_globals);

View file

@ -5,7 +5,7 @@
use by_address::ByAddress;
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::object_tree::*;
use std::collections::HashSet;
use std::rc::Rc;
@ -28,7 +28,7 @@ fn collect_subcomponents_recursive(
hash.insert(ByAddress(component.clone()));
recurse_elem(&component.root_element, &(), &mut |elem: &ElementRc, &()| {
let base_comp = match &elem.borrow().base_type {
Type::Component(base_comp) => {
ElementType::Component(base_comp) => {
if hash.contains(&ByAddress(base_comp.clone())) {
return;
}

View file

@ -11,6 +11,7 @@
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::*;
use crate::langtype::ElementType;
use crate::langtype::Type;
use crate::object_tree::*;
use std::cell::RefCell;
@ -21,19 +22,19 @@ pub fn compile_paths(
tr: &crate::typeregister::TypeRegister,
diag: &mut BuildDiagnostics,
) {
let path_type = tr.lookup("Path");
let path_type = tr.lookup_element("Path").unwrap();
let path_type = path_type.as_builtin();
let pathlayout_type = tr.lookup("PathLayout");
let pathlayout_type = tr.lookup_element("PathLayout").unwrap();
let pathlayout_type = pathlayout_type.as_builtin();
recurse_elem(&component.root_element, &(), &mut |elem_, _| {
let accepted_type = match &elem_.borrow().base_type {
Type::Builtin(be)
ElementType::Builtin(be)
if be.native_class.class_name == path_type.native_class.class_name =>
{
path_type
}
Type::Builtin(be)
ElementType::Builtin(be)
if be.native_class.class_name == pathlayout_type.native_class.class_name =>
{
pathlayout_type
@ -94,7 +95,7 @@ pub fn compile_paths(
if let Some(path_element) = element_types.get(element_name) {
let element_type = match path_element {
Type::Builtin(b) => b.clone(),
ElementType::Builtin(b) => b.clone(),
_ => panic!(
"Incorrect type registry -- expected built-in type for path element {}",
element_name

View file

@ -4,6 +4,7 @@
//! Try to simplify property bindings by propagating constant expressions
use crate::expression_tree::*;
use crate::langtype::ElementType;
use crate::langtype::Type;
use crate::object_tree::*;
@ -152,7 +153,7 @@ fn extract_constant_property_reference(nr: &NamedReference) -> Option<Expression
if let Some(alias) = &decl.is_alias {
return extract_constant_property_reference(alias);
}
} else if let Type::Component(c) = &element.clone().borrow().base_type {
} else if let ElementType::Component(c) = &element.clone().borrow().base_type {
element = c.root_element.clone();
continue;
}

View file

@ -14,16 +14,16 @@ use std::cell::RefCell;
use std::rc::Rc;
use crate::expression_tree::{BindingExpression, Expression, NamedReference};
use crate::langtype::{NativeClass, Type};
use crate::langtype::{ElementType, NativeClass};
use crate::object_tree::{Component, Element, ElementRc};
use crate::typeregister::TypeRegister;
pub fn is_flickable_element(element: &ElementRc) -> bool {
matches!(&element.borrow().base_type, Type::Builtin(n) if n.name == "Flickable")
matches!(&element.borrow().base_type, ElementType::Builtin(n) if n.name == "Flickable")
}
pub fn handle_flickable(root_component: &Rc<Component>, tr: &TypeRegister) {
let mut native_rect = tr.lookup("Rectangle").as_builtin().native_class.clone();
let mut native_rect = tr.lookup_element("Rectangle").unwrap().as_builtin().native_class.clone();
while let Some(p) = native_rect.parent.clone() {
native_rect = p;
}
@ -47,7 +47,7 @@ fn create_viewport_element(flickable_elem: &ElementRc, native_rect: &Rc<NativeCl
let flickable = &mut *flickable;
let viewport = Rc::new(RefCell::new(Element {
id: format!("{}-viewport", flickable.id),
base_type: Type::Native(native_rect.clone()),
base_type: ElementType::Native(native_rect.clone()),
children: std::mem::take(&mut flickable.children),
enclosing_component: flickable.enclosing_component.clone(),
is_flickable_viewport: true,
@ -142,8 +142,8 @@ fn fixup_geometry(flickable_elem: &ElementRc) {
}
/// Return true if this type is a layout that has constraints
fn is_layout(base_type: &Type) -> bool {
if let Type::Builtin(be) = base_type {
fn is_layout(base_type: &ElementType) -> bool {
if let ElementType::Builtin(be) = base_type {
match be.name.as_str() {
"GridLayout" | "HorizontalLayout" | "VerticalLayout" => true,
"PathLayout" => false,

View file

@ -8,7 +8,7 @@ use std::rc::Rc;
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
use crate::expression_tree::{BindingExpression, BuiltinFunction, Expression};
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::object_tree::*;
enum FocusCheckResult {
@ -41,7 +41,7 @@ fn element_focus_check(element: &ElementRc) -> FocusCheckResult {
}
}
if matches!(&element.borrow().base_type.clone(), Type::Builtin(b) if b.accepts_focus) {
if matches!(&element.borrow().base_type.clone(), ElementType::Builtin(b) if b.accepts_focus) {
return FocusCheckResult::ElementIsFocusable;
}

View file

@ -59,7 +59,7 @@ impl crate::generator::ItemTreeBuilder for Helper {
) {
if !component_state {
item.borrow().item_index.set(self.current_item_index).unwrap();
if let crate::langtype::Type::Component(c) = &item.borrow().base_type {
if let crate::langtype::ElementType::Component(c) = &item.borrow().base_type {
generate_item_indices(c);
}
}

View file

@ -4,7 +4,7 @@
//! Inline each object_tree::Component within the main Component
use crate::expression_tree::{BindingExpression, Expression, NamedReference};
use crate::langtype::Type;
use crate::langtype::{ElementType, Type};
use crate::object_tree::*;
use by_address::ByAddress;
use std::cell::RefCell;
@ -22,7 +22,7 @@ pub fn inline(doc: &Document, inline_selection: InlineSelection) {
fn inline_components_recursively(component: &Rc<Component>, inline_selection: InlineSelection) {
recurse_elem(&component.root_element, &(), &mut |elem, _| {
let base = elem.borrow().base_type.clone();
if let Type::Component(c) = base {
if let ElementType::Component(c) = base {
// First, make sure that the component itself is properly inlined
inline_components_recursively(&c, inline_selection);
@ -65,10 +65,7 @@ fn inline_element(
root_component: &Rc<Component>,
) {
// inlined_component must be the base type of this element
debug_assert_eq!(
format!("{:?}", elem.borrow().base_type),
format!("{:?}", Type::Component(inlined_component.clone()))
);
debug_assert_eq!(elem.borrow().base_type, ElementType::Component(inlined_component.clone()));
debug_assert!(
inlined_component.root_element.borrow().repeated.is_none(),
"root element of a component cannot be repeated"
@ -124,7 +121,7 @@ fn inline_element(
elem_mut.children = new_children;
if let Type::Component(c) = &mut elem_mut.base_type {
if let ElementType::Component(c) = &mut elem_mut.base_type {
if c.parent_element.upgrade().is_some() {
debug_assert!(Rc::ptr_eq(elem, &c.parent_element.upgrade().unwrap()));
*c = duplicate_sub_component(c, elem, &mut mapping, priority_delta);
@ -223,7 +220,7 @@ fn duplicate_element_with_mapping(
inline_depth: elem.inline_depth + 1,
}));
mapping.insert(element_key(element.clone()), new.clone());
if let Type::Component(c) = &mut new.borrow_mut().base_type {
if let ElementType::Component(c) = &mut new.borrow_mut().base_type {
if c.parent_element.upgrade().is_some() {
debug_assert!(Rc::ptr_eq(element, &c.parent_element.upgrade().unwrap()));
*c = duplicate_sub_component(c, &new, mapping, priority_delta);

View file

@ -8,6 +8,7 @@ use lyon_path::geom::euclid::approxeq::ApproxEq;
use crate::diagnostics::BuildDiagnostics;
use crate::diagnostics::Spanned;
use crate::expression_tree::*;
use crate::langtype::ElementType;
use crate::langtype::Type;
use crate::layout::*;
use crate::object_tree::*;
@ -25,10 +26,8 @@ pub async fn lower_layouts(
// Ignore import errors
let mut build_diags_to_ignore = crate::diagnostics::BuildDiagnostics::default();
let style_metrics = type_loader
.import_type("std-widgets.slint", "StyleMetrics", &mut build_diags_to_ignore)
.import_component("std-widgets.slint", "StyleMetrics", &mut build_diags_to_ignore)
.await;
let style_metrics =
style_metrics.and_then(|sm| if let Type::Component(c) = sm { Some(c) } else { None });
*component.root_constraints.borrow_mut() =
LayoutConstraints::new(&component.root_element, diag);
@ -53,7 +52,7 @@ fn lower_element_layout(
style_metrics: &Option<Rc<Component>>,
diag: &mut BuildDiagnostics,
) {
let base_type = if let Type::Builtin(base_type) = &elem.borrow().base_type {
let base_type = if let ElementType::Builtin(base_type) = &elem.borrow().base_type {
base_type.clone()
} else {
return;
@ -74,7 +73,10 @@ fn lower_element_layout(
{
let mut elem = elem.borrow_mut();
let elem = &mut *elem;
let prev_base = std::mem::replace(&mut elem.base_type, type_register.lookup("Rectangle"));
let prev_base = std::mem::replace(
&mut elem.base_type,
type_register.lookup_element("Rectangle").unwrap(),
);
// Create fake properties for the layout properties
for p in elem.bindings.keys() {
if !elem.base_type.lookup_property(p).is_valid()
@ -90,7 +92,7 @@ fn lower_element_layout(
}
pub fn is_layout_element(element: &ElementRc) -> bool {
matches!(&element.borrow().base_type, Type::Builtin(n) if n.name == "GridLayout" || n.name == "HorizontalLayout" || n.name == "VerticalLayout" || n.name == "PathLayout")
matches!(&element.borrow().base_type, ElementType::Builtin(n) if n.name == "GridLayout" || n.name == "HorizontalLayout" || n.name == "VerticalLayout" || n.name == "PathLayout")
}
fn lower_grid_layout(
@ -119,7 +121,7 @@ fn lower_grid_layout(
let layout_children = std::mem::take(&mut grid_layout_element.borrow_mut().children);
let mut collected_children = Vec::new();
for layout_child in layout_children {
let is_row = if let Type::Builtin(be) = &layout_child.borrow().base_type {
let is_row = if let ElementType::Builtin(be) = &layout_child.borrow().base_type {
be.name == "Row"
} else {
false

View file

@ -5,7 +5,7 @@
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::{Expression, NamedReference};
use crate::langtype::Type;
use crate::langtype::{ElementType, Type};
use crate::object_tree::*;
use crate::typeregister::TypeRegister;
use std::cell::RefCell;
@ -34,7 +34,7 @@ pub fn lower_popups(
fn lower_popup_window(
popup_window_element: &ElementRc,
parent_element: Option<&ElementRc>,
window_type: &Type,
window_type: &ElementType,
diag: &mut BuildDiagnostics,
) {
let parent_element = match parent_element {

View file

@ -6,6 +6,7 @@
use crate::diagnostics::BuildDiagnostics;
use crate::diagnostics::SourceLocation;
use crate::expression_tree::*;
use crate::langtype::ElementType;
use crate::langtype::Type;
use crate::object_tree::*;
use std::cell::RefCell;
@ -229,7 +230,7 @@ fn expression_for_property(element: &ElementRc, name: &str) -> ExpressionForProp
return ExpressionForProperty::Expression(e.expression.clone());
}
}
element_it = if let Type::Component(base) = &element.borrow().base_type {
element_it = if let ElementType::Component(base) = &element.borrow().base_type {
in_base = true;
Some(base.root_element.clone())
} else {

View file

@ -10,7 +10,7 @@
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::{BindingExpression, Expression, NamedReference, Unit};
use crate::langtype::Type;
use crate::langtype::{ElementType, Type};
use crate::object_tree::*;
use std::cell::RefCell;
use std::rc::Rc;
@ -23,15 +23,15 @@ pub async fn lower_tabwidget(
// Ignore import errors
let mut build_diags_to_ignore = BuildDiagnostics::default();
let tabwidget_impl = type_loader
.import_type("std-widgets.slint", "TabWidgetImpl", &mut build_diags_to_ignore)
.import_component("std-widgets.slint", "TabWidgetImpl", &mut build_diags_to_ignore)
.await
.expect("can't load TabWidgetImpl from std-widgets.slint");
let tab_impl = type_loader
.import_type("std-widgets.slint", "TabImpl", &mut build_diags_to_ignore)
.import_component("std-widgets.slint", "TabImpl", &mut build_diags_to_ignore)
.await
.expect("can't load TabImpl from std-widgets.slint");
let tabbar_impl = type_loader
.import_type("std-widgets.slint", "TabBarImpl", &mut build_diags_to_ignore)
.import_component("std-widgets.slint", "TabBarImpl", &mut build_diags_to_ignore)
.await
.expect("can't load TabBarImpl from std-widgets.slint");
let rectangle_type =
@ -41,9 +41,9 @@ pub async fn lower_tabwidget(
if elem.borrow().base_type.to_string() == "TabWidget" {
process_tabwidget(
elem,
&tabwidget_impl,
&tab_impl,
&tabbar_impl,
ElementType::Component(tabwidget_impl.clone()),
ElementType::Component(tab_impl.clone()),
ElementType::Component(tabbar_impl.clone()),
&rectangle_type,
diag,
);
@ -53,13 +53,13 @@ pub async fn lower_tabwidget(
fn process_tabwidget(
elem: &ElementRc,
tabwidget_impl: &Type,
tab_impl: &Type,
tabbar_impl: &Type,
rectangle_type: &Type,
tabwidget_impl: ElementType,
tab_impl: ElementType,
tabbar_impl: ElementType,
rectangle_type: &ElementType,
diag: &mut BuildDiagnostics,
) {
elem.borrow_mut().base_type = tabwidget_impl.clone();
elem.borrow_mut().base_type = tabwidget_impl;
let mut children = std::mem::take(&mut elem.borrow_mut().children);
let num_tabs = children.len();
let mut tabs = Vec::new();

View file

@ -7,7 +7,7 @@
use crate::diagnostics::Spanned;
use crate::expression_tree::{BindingExpression, Expression, Unit};
use crate::langtype::Type;
use crate::langtype::{ElementType, Type};
use crate::layout::Orientation;
use crate::namedreference::NamedReference;
use crate::object_tree::*;
@ -84,19 +84,19 @@ fn must_initialize(elem: &Element, prop: &str) -> bool {
/// Returns a type if the property needs to be materialized.
fn should_materialize(
property_declarations: &BTreeMap<String, PropertyDeclaration>,
base_type: &Type,
base_type: &ElementType,
prop: &str,
) -> Option<Type> {
if property_declarations.contains_key(prop) {
return None;
}
let has_declared_property = match &base_type {
Type::Component(c) => has_declared_property(&c.root_element.borrow(), prop),
Type::Builtin(b) => b.properties.contains_key(prop),
Type::Native(n) => {
ElementType::Component(c) => has_declared_property(&c.root_element.borrow(), prop),
ElementType::Builtin(b) => b.properties.contains_key(prop),
ElementType::Native(n) => {
n.lookup_property(prop).map_or(false, |prop_type| prop_type.is_property_type())
}
_ => false,
ElementType::Global | ElementType::Error => false,
};
if !has_declared_property {
@ -115,10 +115,10 @@ fn has_declared_property(elem: &Element, prop: &str) -> bool {
return true;
}
match &elem.base_type {
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,
ElementType::Component(c) => has_declared_property(&c.root_element.borrow(), prop),
ElementType::Builtin(b) => b.properties.contains_key(prop),
ElementType::Native(n) => n.lookup_property(prop).is_some(),
ElementType::Global | ElementType::Error => false,
}
}

View file

@ -4,9 +4,9 @@
//! This pass moves all declaration of properties or callback to the root
use crate::expression_tree::NamedReference;
use crate::langtype::Type;
use crate::object_tree::*;
use crate::langtype::ElementType;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::rc::Rc;
@ -36,7 +36,7 @@ fn do_move_declarations(component: &Rc<Component>) {
visit_all_named_references_in_element(elem, fixup_reference);
if elem.borrow().repeated.is_some() {
if let Type::Component(base) = &elem.borrow().base_type {
if let ElementType::Component(base) = &elem.borrow().base_type {
do_move_declarations(base);
} else {
panic!("Repeated element should have a component as base because of the repeater_component.rs pass")
@ -134,7 +134,7 @@ fn simplify_optimized_items_recursive(component: &Rc<Component>) {
.for_each(|f| simplify_optimized_items_recursive(&f.component));
recurse_elem(&component.root_element, &(), &mut |elem, _| {
if elem.borrow().repeated.is_some() {
if let Type::Component(base) = &elem.borrow().base_type {
if let ElementType::Component(base) = &elem.borrow().base_type {
simplify_optimized_items_recursive(base);
}
}
@ -147,41 +147,22 @@ fn simplify_optimized_items_recursive(component: &Rc<Component>) {
fn simplify_optimized_items(items: &[ElementRc]) {
for elem in items {
recurse_elem(elem, &(), &mut |elem, _| {
let mut base_type_it = core::mem::take(&mut elem.borrow_mut().base_type);
loop {
base_type_it = match base_type_it {
Type::Component(c) => {
elem.borrow_mut().property_declarations.extend(
c.root_element
.borrow()
.property_declarations
.iter()
.map(|(k, v)| (k.clone(), v.clone())),
);
todo!(
"Move the bindings from the component as well.
But this actually should not happen because of inlining"
);
#[allow(unreachable_code)]
c.root_element.borrow().base_type.clone()
}
Type::Builtin(c) => {
// This assume that all properties of builtin items are fine with the default value
elem.borrow_mut().property_declarations.extend(c.properties.iter().map(
|(k, v)| {
(
k.clone(),
PropertyDeclaration {
property_type: v.ty.clone(),
..Default::default()
},
)
let base = core::mem::take(&mut elem.borrow_mut().base_type);
if let ElementType::Builtin(c) = base {
// This assume that all properties of builtin items are fine with the default value
elem.borrow_mut().property_declarations.extend(c.properties.iter().map(
|(k, v)| {
(
k.clone(),
PropertyDeclaration {
property_type: v.ty.clone(),
..Default::default()
},
));
Type::Invalid
}
_ => break,
}
)
},
));
} else {
unreachable!("Only builtin items should be optimized")
}
})
}

View file

@ -6,7 +6,8 @@
//! Rectangles which do not draw anything and have no x or y don't need to be in
//! the item tree, we can just remove them.
use crate::{langtype::Type, object_tree::*};
use crate::langtype::ElementType;
use crate::object_tree::*;
use std::rc::Rc;
pub fn optimize_useless_rectangles(root_component: &Rc<Component>) {
@ -46,7 +47,7 @@ fn can_optimize(elem: &ElementRc) -> bool {
}
let base_type = match &e.base_type {
Type::Builtin(base_type) if base_type.name == "Rectangle" => base_type,
ElementType::Builtin(base_type) if base_type.name == "Rectangle" => base_type,
_ => return false,
};

View file

@ -6,7 +6,7 @@ Make sure that the Repeated expression are just components without any children
*/
use crate::expression_tree::{Expression, NamedReference};
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::object_tree::*;
use std::cell::RefCell;
use std::rc::Rc;
@ -78,7 +78,7 @@ fn create_repeater_components(component: &Rc<Component>) {
e.borrow_mut().enclosing_component = weak.clone()
});
create_repeater_components(&comp);
elem.base_type = Type::Component(comp);
elem.base_type = ElementType::Component(comp);
});
for p in component.popup_windows.borrow().iter() {
@ -95,7 +95,7 @@ fn adjust_references(comp: &Rc<Component>) {
}
let e = nr.element();
if e.borrow().repeated.is_some() {
if let Type::Component(c) = e.borrow().base_type.clone() {
if let ElementType::Component(c) = e.borrow().base_type.clone() {
*nr = NamedReference::new(&c.root_element, nr.name())
};
}

View file

@ -7,7 +7,7 @@
use std::collections::HashSet;
use std::rc::Rc;
use crate::langtype::{NativeClass, Type};
use crate::langtype::{ElementType, NativeClass};
use crate::object_tree::{recurse_elem_including_sub_components, Component};
pub fn resolve_native_classes(component: &Component) {
@ -16,16 +16,16 @@ pub fn resolve_native_classes(component: &Component) {
let elem = elem.borrow();
let base_type = match &elem.base_type {
Type::Component(_) => {
ElementType::Component(_) => {
// recurse_elem_including_sub_components will recurse into it
return;
}
Type::Builtin(b) => b,
Type::Native(_) => {
ElementType::Builtin(b) => b,
ElementType::Native(_) => {
// already native
return;
}
_ => panic!("This should not happen"),
ElementType::Global | ElementType::Error => panic!("This should not happen"),
};
let analysis = elem.property_analysis.borrow();
@ -45,7 +45,7 @@ pub fn resolve_native_classes(component: &Component) {
)
};
elem.borrow_mut().base_type = Type::Native(new_native_class);
elem.borrow_mut().base_type = ElementType::Native(new_native_class);
})
}
@ -85,7 +85,7 @@ fn select_minimal_class_based_on_property_usage<'a>(
#[test]
fn test_select_minimal_class_based_on_property_usage() {
use crate::langtype::BuiltinPropertyInfo;
use crate::langtype::{BuiltinPropertyInfo, Type};
let first = Rc::new(NativeClass::new_with_properties(
"first_class",
[("first_prop".to_owned(), BuiltinPropertyInfo::new(Type::Int32))].iter().cloned(),
@ -120,7 +120,7 @@ fn test_select_minimal_class_based_on_property_usage() {
fn select_minimal_class() {
let tr = crate::typeregister::TypeRegister::builtin();
let tr = tr.borrow();
let rect = tr.lookup("Rectangle");
let rect = tr.lookup_element("Rectangle").unwrap();
let rect = rect.as_builtin();
assert_eq!(
select_minimal_class_based_on_property_usage(

View file

@ -10,7 +10,7 @@
use crate::diagnostics::{BuildDiagnostics, Spanned};
use crate::expression_tree::*;
use crate::langtype::Type;
use crate::langtype::{ElementType, Type};
use crate::lookup::{LookupCtx, LookupObject, LookupResult};
use crate::object_tree::*;
use crate::parser::{identifier_text, syntax_nodes, NodeOrToken, SyntaxKind, SyntaxNode};
@ -1070,14 +1070,15 @@ fn continue_lookup_within_element(
} else {
let mut err = |extra: &str| {
let what = match &elem.borrow().base_type {
Type::Void => {
ElementType::Global => {
let global = elem.borrow().enclosing_component.upgrade().unwrap();
assert!(global.is_global());
format!("'{}'", global.id)
}
Type::Component(c) => format!("Element '{}'", c.id),
Type::Builtin(b) => format!("Element '{}'", b.name),
_ => {
ElementType::Component(c) => format!("Element '{}'", c.id),
ElementType::Builtin(b) => format!("Element '{}'", b.name),
ElementType::Native(_) => unreachable!("the native pass comes later"),
ElementType::Error => {
assert!(ctx.diag.has_error());
return;
}

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use crate::diagnostics::BuildDiagnostics;
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::object_tree::*;
use std::collections::HashMap;
use std::rc::Rc;
@ -38,7 +38,7 @@ fn rename_globals(component: &Rc<Component>, mut count: u32) {
for g in &component.used_types.borrow().globals {
count += 1;
let mut root = g.root_element.borrow_mut();
if matches!(&root.base_type, Type::Builtin(_)) {
if matches!(&root.base_type, ElementType::Builtin(_)) {
// builtin global keeps its name
root.id = g.id.clone();
} else if let Some(s) = g.exported_global_names.borrow().first() {

View file

@ -7,12 +7,13 @@ use std::cell::RefCell;
use std::rc::Rc;
use crate::expression_tree::{Expression, NamedReference};
use crate::langtype::{NativeClass, Type};
use crate::langtype::{ElementType, NativeClass, Type};
use crate::object_tree::{self, Component, Element, ElementRc};
use crate::typeregister::TypeRegister;
pub fn handle_visible(component: &Rc<Component>, type_register: &TypeRegister) {
let native_clip = type_register.lookup("Clip").as_builtin().native_class.clone();
let native_clip =
type_register.lookup_element("Clip").unwrap().as_builtin().native_class.clone();
crate::object_tree::recurse_elem_including_sub_components(
component,
@ -67,7 +68,7 @@ pub fn handle_visible(component: &Rc<Component>, type_register: &TypeRegister) {
fn create_visibility_element(child: &ElementRc, native_clip: &Rc<NativeClass>) -> ElementRc {
let element = Element {
id: format!("{}-visibility", child.borrow().id),
base_type: Type::Native(native_clip.clone()),
base_type: ElementType::Native(native_clip.clone()),
enclosing_component: child.borrow().enclosing_component.clone(),
bindings: std::iter::once((
"clip".to_owned(),

View file

@ -8,7 +8,7 @@ use std::rc::Rc;
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::{Expression, Unit};
use crate::langtype::Type;
use crate::langtype::ElementType;
use crate::object_tree::{Component, ElementRc};
pub fn reorder_by_z_order(root_component: &Rc<Component>, diag: &mut BuildDiagnostics) {
@ -36,7 +36,7 @@ fn reorder_children_by_zorder(
let z =
z.or_else(|| {
child_elm.borrow().repeated.as_ref()?;
if let Type::Component(c) = &child_elm.borrow().base_type {
if let ElementType::Component(c) = &child_elm.borrow().base_type {
c.root_element.borrow_mut().bindings.remove("z").and_then(|e| {
eval_const_expr(&e.borrow().expression, "z", &*e.borrow(), diag)
})

View file

@ -23,6 +23,6 @@ Foo := Rectangle {
xx := Rectangle { }
Comp {
r: xx;
// ^error{Cannot assign to r in Comp}
// ^error{Unknown property}
}
}

View file

@ -159,12 +159,12 @@ impl TypeLoader {
foreign_imports
}
pub async fn import_type(
pub async fn import_component(
&mut self,
file_to_import: &str,
type_name: &str,
diagnostics: &mut BuildDiagnostics,
) -> Option<crate::langtype::Type> {
) -> Option<Rc<object_tree::Component>> {
let doc_path = match self.ensure_document_loaded(file_to_import, None, diagnostics).await {
Some(doc_path) => doc_path,
None => return None,
@ -172,9 +172,9 @@ impl TypeLoader {
let doc = self.all_documents.docs.get(&doc_path).unwrap();
doc.exports().iter().find_map(|(export_name, ty)| {
doc.exports.0.iter().find_map(|(export_name, ty)| {
if type_name == export_name.as_str() {
Some(ty.clone())
ty.clone().left()
} else {
None
}
@ -358,10 +358,9 @@ impl TypeLoader {
};
let doc = self.all_documents.docs.get(&doc_path).unwrap();
let exports = doc.exports();
for import_name in imported_types {
let imported_type = exports.iter().find_map(|(export_name, ty)| {
let imported_type = doc.exports.0.iter().find_map(|(export_name, ty)| {
if import_name.external_name == export_name.as_str() {
Some(ty.clone())
} else {
@ -383,9 +382,14 @@ impl TypeLoader {
}
};
registry_to_populate
.borrow_mut()
.insert_type_with_name(imported_type, import_name.internal_name);
match imported_type {
itertools::Either::Left(c) => registry_to_populate
.borrow_mut()
.add_with_name(import_name.internal_name, c),
itertools::Either::Right(ty) => registry_to_populate
.borrow_mut()
.insert_type_with_name(ty, import_name.internal_name),
}
}
})
}
@ -565,8 +569,11 @@ fn test_manual_import() {
let mut build_diagnostics = BuildDiagnostics::default();
let mut loader = TypeLoader::new(global_registry, compiler_config, &mut build_diagnostics);
let maybe_button_type =
spin_on::spin_on(loader.import_type("std-widgets.slint", "Button", &mut build_diagnostics));
let maybe_button_type = spin_on::spin_on(loader.import_component(
"std-widgets.slint",
"Button",
&mut build_diagnostics,
));
assert!(!build_diagnostics.has_error());
assert!(maybe_button_type.is_some());

View file

@ -8,7 +8,9 @@ use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use crate::expression_tree::{BuiltinFunction, Expression};
use crate::langtype::{BuiltinPropertyInfo, Enumeration, PropertyLookupResult, Type};
use crate::langtype::{
BuiltinElement, BuiltinPropertyInfo, ElementType, Enumeration, PropertyLookupResult, Type,
};
use crate::object_tree::Component;
pub const RESERVED_GEOMETRY_PROPERTIES: &[(&str, Type)] = &[
@ -183,10 +185,12 @@ pub fn reserved_member_function(name: &str) -> Expression {
#[derive(Debug, Default)]
pub struct TypeRegister {
/// The set of types.
/// The set of property types.
types: HashMap<String, Type>,
/// The set of element types
elements: HashMap<String, ElementType>,
supported_property_animation_types: HashSet<String>,
pub(crate) property_animation_type: Type,
pub(crate) property_animation_type: ElementType,
/// Map from a context restricted type to the list of contexts (parent type) it is allowed in. This is
/// used to construct helpful error messages, such as "Row can only be within a GridLayout element".
context_restricted_types: HashMap<String, HashSet<String>>,
@ -236,13 +240,13 @@ impl TypeRegister {
let mut context_restricted_types = HashMap::new();
register
.types
.elements
.values()
.for_each(|ty| ty.collect_contextual_types(&mut context_restricted_types));
register.context_restricted_types = context_restricted_types;
match &mut register.types.get_mut("PopupWindow").unwrap() {
Type::Builtin(ref mut b) => {
match &mut register.elements.get_mut("PopupWindow").unwrap() {
ElementType::Builtin(ref mut b) => {
Rc::get_mut(b).unwrap().properties.insert(
"show".into(),
BuiltinPropertyInfo::new(BuiltinFunction::ShowPopupWindow.ty()),
@ -277,8 +281,8 @@ impl TypeRegister {
fn lookup_element_as_result(
&self,
name: &str,
) -> Result<Type, HashMap<String, HashSet<String>>> {
match self.types.get(name).cloned() {
) -> Result<ElementType, HashMap<String, HashSet<String>>> {
match self.elements.get(name).cloned() {
Some(ty) => Ok(ty),
None => match &self.parent_registry {
Some(r) => r.borrow().lookup_element_as_result(name),
@ -287,7 +291,7 @@ impl TypeRegister {
}
}
pub fn lookup_element(&self, name: &str) -> Result<Type, String> {
pub fn lookup_element(&self, name: &str) -> Result<ElementType, String> {
self.lookup_element_as_result(name).map_err(|context_restricted_types| {
if let Some(permitted_parent_types) = context_restricted_types.get(name) {
if permitted_parent_types.len() == 1 {
@ -305,6 +309,8 @@ impl TypeRegister {
elements.join(", ")
)
}
} else if let Some(ty) = self.types.get(name) {
format!("'{}' cannot be used as an element", ty)
} else {
format!("Unknown type {}", name)
}
@ -323,10 +329,14 @@ impl TypeRegister {
}
pub fn add_with_name(&mut self, name: String, comp: Rc<Component>) {
self.types.insert(name, Type::Component(comp));
self.elements.insert(name, ElementType::Component(comp));
}
pub fn property_animation_type_for_property(&self, property_type: Type) -> Type {
pub fn add_builtin(&mut self, builtin: Rc<BuiltinElement>) {
self.elements.insert(builtin.name.clone(), ElementType::Builtin(builtin));
}
pub fn property_animation_type_for_property(&self, property_type: Type) -> ElementType {
if self.supported_property_animation_types.contains(&property_type.to_string()) {
self.property_animation_type.clone()
} else {
@ -348,4 +358,14 @@ impl TypeRegister {
}
all
}
/// Return a hashmap with all the registered element type
pub fn all_elements(&self) -> HashMap<String, ElementType> {
let mut all =
self.parent_registry.as_ref().map(|r| r.borrow().all_elements()).unwrap_or_default();
for (k, v) in &self.elements {
all.insert(k.clone(), v.clone());
}
all
}
}

View file

@ -9,7 +9,7 @@ use core::convert::TryInto;
use core::ptr::NonNull;
use dynamic_type::{Instance, InstanceBox};
use i_slint_compiler::expression_tree::{Expression, NamedReference};
use i_slint_compiler::langtype::Type;
use i_slint_compiler::langtype::{ElementType, Type};
use i_slint_compiler::object_tree::ElementRc;
use i_slint_compiler::*;
use i_slint_compiler::{diagnostics::BuildDiagnostics, object_tree::PropertyDeclaration};
@ -754,7 +754,10 @@ pub async fn load(
if diag.has_error() {
return (Err(()), diag);
}
if matches!(doc.root_component.root_element.borrow().base_type, Type::Invalid | Type::Void) {
if matches!(
doc.root_component.root_element.borrow().base_type,
ElementType::Global | ElementType::Error
) {
diag.push_error_with_span("No component found".into(), Default::default());
return (Err(()), diag);
}

View file

@ -954,9 +954,6 @@ fn check_value_type(value: &Value, ty: &Type) -> bool {
Type::Invalid
| Type::InferredProperty
| Type::InferredCallback
| Type::Component(_)
| Type::Builtin(_)
| Type::Native(_)
| Type::Callback { .. }
| Type::Function { .. }
| Type::ElementReference => panic!("not valid property type"),
@ -1260,9 +1257,6 @@ pub fn default_value_for_type(ty: &Type) -> Value {
Type::InferredProperty
| Type::InferredCallback
| Type::ElementReference
| Type::Builtin(_)
| Type::Component(_)
| Type::Native(_)
| Type::Function { .. } => {
panic!("There can't be such property")
}

View file

@ -8,9 +8,10 @@ use std::rc::Rc;
use crate::api::Value;
use crate::dynamic_component::{ErasedComponentBox, ErasedComponentDescription};
use crate::SetPropertyError;
use i_slint_compiler::langtype::ElementType;
use i_slint_compiler::namedreference::NamedReference;
use i_slint_compiler::object_tree::Component;
use i_slint_compiler::object_tree::PropertyDeclaration;
use i_slint_compiler::{langtype::Type, object_tree::Component};
use i_slint_core::component::ComponentVTable;
use i_slint_core::rtti;
use i_slint_core::window::WindowAdapter;
@ -228,18 +229,18 @@ impl<T: rtti::BuiltinItem + 'static> GlobalComponent for T {
pub(crate) fn generate(component: &Rc<Component>) -> CompiledGlobal {
debug_assert!(component.is_global());
match &component.root_element.borrow().base_type {
Type::Void => {
ElementType::Global => {
generativity::make_guard!(guard);
CompiledGlobal::Component {
component: crate::dynamic_component::generate_component(component, guard).into(),
public_properties: Default::default(),
}
}
Type::Builtin(b) => CompiledGlobal::Builtin {
ElementType::Builtin(b) => CompiledGlobal::Builtin {
name: component.id.clone(),
element: b.clone(),
public_properties: Default::default(),
},
_ => unreachable!(),
ElementType::Error | ElementType::Native(_) | ElementType::Component(_) => unreachable!(),
}
}

View file

@ -7,7 +7,7 @@ use super::DocumentCache;
use crate::wasm_prelude::*;
use i_slint_compiler::diagnostics::Spanned;
use i_slint_compiler::expression_tree::Expression;
use i_slint_compiler::langtype::Type;
use i_slint_compiler::langtype::{ElementType, Type};
use i_slint_compiler::lookup::{LookupCtx, LookupObject, LookupResult};
use i_slint_compiler::parser::{syntax_nodes, SyntaxKind, SyntaxToken};
use lsp_types::{
@ -145,7 +145,7 @@ pub(crate) fn completion_at(
if available_types.contains(&exported_name.name) {
continue;
}
if let Type::Component(c) = ty {
if let Some(c) = ty.as_ref().left() {
if c.is_global() {
continue;
}
@ -290,14 +290,12 @@ pub(crate) fn completion_at(
.map(|doc| &doc.local_registry)
.unwrap_or(&global_tr);
return Some(
tr.all_types()
tr.all_elements()
.into_iter()
// manually filter deprecated or undocumented cases
.filter(|(k, _)| k != "Clip")
.filter_map(|(k, t)| {
match t {
Type::Component(c) if !c.is_global() => (),
Type::Builtin(b) if !b.is_internal && !b.is_global => (),
ElementType::Component(c) if !c.is_global() => (),
ElementType::Builtin(b) if !b.is_internal && !b.is_global => (),
_ => return None,
};
let mut c = CompletionItem::new_simple(k, "element".into());
@ -423,10 +421,10 @@ fn resolve_element_scope(
});
Some(c)
}))
.chain(tr.all_types().into_iter().filter_map(|(k, t)| {
.chain(tr.all_elements().into_iter().filter_map(|(k, t)| {
match t {
Type::Component(c) if !c.is_global() => (),
Type::Builtin(b) if !b.is_internal && !b.is_global => (),
ElementType::Component(c) if !c.is_global() => (),
ElementType::Builtin(b) if !b.is_internal && !b.is_global => (),
_ => return None,
};
let mut c = CompletionItem::new_simple(k, "element".into());

View file

@ -8,7 +8,7 @@ use super::DocumentCache;
use crate::wasm_prelude::*;
use i_slint_compiler::diagnostics::Spanned;
use i_slint_compiler::expression_tree::Expression;
use i_slint_compiler::langtype::Type;
use i_slint_compiler::langtype::{ElementType, Type};
use i_slint_compiler::lookup::{LookupObject, LookupResult};
use i_slint_compiler::parser::{syntax_nodes, SyntaxKind, SyntaxNode, SyntaxToken};
use lsp_types::{GotoDefinitionResponse, LocationLink, Range, Url};
@ -22,19 +22,26 @@ pub fn goto_definition(
if let Some(n) = syntax_nodes::QualifiedName::new(node.clone()) {
let parent = n.parent()?;
return match parent.kind() {
SyntaxKind::Element | SyntaxKind::Type => {
SyntaxKind::Type => {
let qual = i_slint_compiler::object_tree::QualifiedTypeName::from_node(n);
let doc = document_cache.documents.get_document(node.source_file.path())?;
match doc.local_registry.lookup_qualified(&qual.members) {
i_slint_compiler::langtype::Type::Component(c) => {
goto_node(document_cache, &*c.root_element.borrow().node.as_ref()?)
}
i_slint_compiler::langtype::Type::Struct { node: Some(node), .. } => {
Type::Struct { node: Some(node), .. } => {
goto_node(document_cache, node.parent().as_ref()?)
}
_ => None,
}
}
SyntaxKind::Element => {
let qual = i_slint_compiler::object_tree::QualifiedTypeName::from_node(n);
let doc = document_cache.documents.get_document(node.source_file.path())?;
match doc.local_registry.lookup_element(&qual.to_string()) {
Ok(ElementType::Component(c)) => {
goto_node(document_cache, &*c.root_element.borrow().node.as_ref()?)
}
_ => None,
}
}
SyntaxKind::Expression => {
if token.kind() != SyntaxKind::Identifier {
return None;
@ -73,7 +80,7 @@ pub fn goto_definition(
break (**x.node.as_ref()?).clone();
}
let base = el.borrow().base_type.clone();
if let Type::Component(c) = base {
if let ElementType::Component(c) = base {
el = c.root_element.clone();
} else {
return None;
@ -89,8 +96,8 @@ pub fn goto_definition(
} else if let Some(n) = syntax_nodes::ImportIdentifier::new(node.clone()) {
let doc = document_cache.documents.get_document(node.source_file.path())?;
let imp_name = i_slint_compiler::typeloader::ImportedName::from_node(n);
return match doc.local_registry.lookup(&imp_name.internal_name) {
i_slint_compiler::langtype::Type::Component(c) => {
return match doc.local_registry.lookup_element(&imp_name.internal_name) {
Ok(ElementType::Component(c)) => {
goto_node(document_cache, &*c.root_element.borrow().node.as_ref()?)
}
_ => None,
@ -176,7 +183,7 @@ fn find_property_declaration_in_base(
.unwrap_or(&global_tr);
let mut element_type = crate::util::lookup_current_element_type((*element).clone(), tr)?;
while let Type::Component(com) = element_type {
while let ElementType::Component(com) = element_type {
if let Some(p) = com.root_element.borrow().property_declarations.get(prop_name) {
return p.node.as_ref().map(|x| (**x).clone());
}

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use i_slint_compiler::diagnostics::Spanned;
use i_slint_compiler::langtype::Type;
use i_slint_compiler::langtype::{ElementType, Type};
use i_slint_compiler::object_tree::{Element, ElementRc};
use i_slint_compiler::parser::{syntax_nodes, SyntaxKind};
use std::collections::HashSet;
@ -187,7 +187,7 @@ fn get_properties(
loop {
let base_type = current_element.borrow().base_type.clone();
match base_type {
Type::Component(c) => {
ElementType::Component(c) => {
current_element = c.root_element.clone();
result.extend(get_element_properties(
&current_element.borrow(),
@ -196,7 +196,7 @@ fn get_properties(
));
continue;
}
Type::Builtin(b) => {
ElementType::Builtin(b) => {
result.extend(b.properties.iter().filter_map(|(k, t)| {
if geometry_prop.contains(k.as_str()) {
// skip geometry property because they are part of the reserved ones
@ -255,10 +255,10 @@ fn get_properties(
));
}
}
Type::Void => {
// a global
ElementType::Global => {
break;
}
_ => {}
}

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
use i_slint_compiler::diagnostics::{DiagnosticLevel, Spanned};
use i_slint_compiler::langtype::Type;
use i_slint_compiler::langtype::ElementType;
use i_slint_compiler::lookup::LookupCtx;
use i_slint_compiler::object_tree;
use i_slint_compiler::parser::{syntax_nodes, SyntaxKind, SyntaxNode};
@ -23,7 +23,7 @@ use crate::DocumentCache;
/// }
/// }
/// ```
pub fn lookup_current_element_type(mut node: SyntaxNode, tr: &TypeRegister) -> Option<Type> {
pub fn lookup_current_element_type(mut node: SyntaxNode, tr: &TypeRegister) -> Option<ElementType> {
while node.kind() != SyntaxKind::Element {
if let Some(parent) = node.parent() {
node = parent
@ -80,9 +80,12 @@ pub fn with_lookup_ctx<R>(
};
let component = i_slint_compiler::parser::identifier_text(&component.DeclaredIdentifier())
.map(|component_name| tr.lookup(&component_name))?;
let scope =
if let Type::Component(c) = component { vec![c.root_element.clone()] } else { Vec::new() };
.and_then(|component_name| tr.lookup_element(&component_name).ok())?;
let scope = if let ElementType::Component(c) = component {
vec![c.root_element.clone()]
} else {
Vec::new()
};
let mut build_diagnostics = Default::default();
let mut lookup_context = LookupCtx::empty_context(tr, &mut build_diagnostics);