mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-01 12:24:16 +00:00
WIP: pure qualifier for callback and functions
This commit is contained in:
parent
8a09043e63
commit
1cbd61145e
34 changed files with 366 additions and 93 deletions
|
|
@ -940,7 +940,7 @@ It is possible to re-expose a callback or properties from a global using the two
|
|||
```slint,no-preview
|
||||
global Logic := {
|
||||
property <int> the-value;
|
||||
callback magic-operation(int) -> int;
|
||||
pure callback magic-operation(int) -> int;
|
||||
}
|
||||
|
||||
SomeComponent := Text {
|
||||
|
|
@ -952,7 +952,7 @@ export MainWindow := Window {
|
|||
// re-expose the global properties such that the native code
|
||||
// can access or modify them
|
||||
property the-value <=> Logic.the-value;
|
||||
callback magic-operation <=> Logic.magic-operation;
|
||||
pure callback magic-operation <=> Logic.magic-operation;
|
||||
|
||||
SomeComponent {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ connected to the native code.
|
|||
import { HorizontalBox, VerticalBox, LineEdit } from "std-widgets.slint";
|
||||
|
||||
export global Logic := {
|
||||
callback to-upper-case(string) -> string;
|
||||
pure callback to-upper-case(string) -> string;
|
||||
// You can collect other global properties here
|
||||
}
|
||||
|
||||
|
|
@ -486,7 +486,7 @@ import { HorizontalBox, Button } from "std-widgets.slint";
|
|||
|
||||
export global Tr := {
|
||||
// Do the translation of the first argument, with an array of string as supstitution
|
||||
callback gettext(string, [string]) -> string;
|
||||
pure callback gettext(string, [string]) -> string;
|
||||
|
||||
// A default implementation that returns the original string for preview purposes.
|
||||
gettext(text, _) => { return text; }
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import { LineEdit, Button, ComboBox, VerticalBox } from "std-widgets.slint";
|
|||
|
||||
Booker := Window {
|
||||
// returns true if the string parameter is a valid date
|
||||
callback validate-date(string) -> bool;
|
||||
pure callback validate-date(string) -> bool;
|
||||
validate-date(_) => { true }
|
||||
// returns true if the first date is before the second date and they are both valid
|
||||
callback compare-date(string, string) -> bool;
|
||||
pure callback compare-date(string, string) -> bool;
|
||||
compare-date(a, b) => { a <= b }
|
||||
property <bool> message-visible;
|
||||
VerticalBox {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ slint::slint! {
|
|||
|
||||
property original-image <=> original.source;
|
||||
property filters <=> filter-combo.model;
|
||||
callback filter-image(int) -> image;
|
||||
pure callback filter-image(int) -> image;
|
||||
|
||||
HorizontalBox {
|
||||
VerticalBox {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export MainWindow := Window {
|
|||
preferred-width: 800px;
|
||||
preferred-height: 600px;
|
||||
|
||||
callback render_plot(float /* pitch */, float /* yaw */, float /* amplitude */) -> image;
|
||||
pure callback render_plot(float /* pitch */, float /* yaw */, float /* amplitude */) -> image;
|
||||
|
||||
property <float> pitch: 0.15;
|
||||
property <float> yaw: 0.5;
|
||||
|
|
|
|||
|
|
@ -172,8 +172,8 @@ impl BuiltinFunction {
|
|||
}
|
||||
}
|
||||
|
||||
/// It is pure if the return value only depends on its argument and has no side effect
|
||||
fn is_pure(&self) -> bool {
|
||||
/// It is const if the return value only depends on its argument and has no side effect
|
||||
fn is_const(&self) -> bool {
|
||||
match self {
|
||||
BuiltinFunction::GetWindowScaleFactor => false,
|
||||
BuiltinFunction::GetWindowDefaultFontSize => false,
|
||||
|
|
@ -215,6 +215,43 @@ impl BuiltinFunction {
|
|||
| BuiltinFunction::RegisterBitmapFont => false,
|
||||
}
|
||||
}
|
||||
|
||||
// It is pure if it has no side effect
|
||||
pub fn is_pure(&self) -> bool {
|
||||
match self {
|
||||
BuiltinFunction::GetWindowScaleFactor => true,
|
||||
BuiltinFunction::GetWindowDefaultFontSize => true,
|
||||
BuiltinFunction::AnimationTick => true,
|
||||
BuiltinFunction::DarkColorScheme => true,
|
||||
// Even if it has technically side effect, we still consider it as pure for our purpose
|
||||
BuiltinFunction::Debug => true,
|
||||
BuiltinFunction::Mod
|
||||
| BuiltinFunction::Round
|
||||
| BuiltinFunction::Ceil
|
||||
| BuiltinFunction::Floor
|
||||
| BuiltinFunction::Abs
|
||||
| BuiltinFunction::Sqrt
|
||||
| BuiltinFunction::Cos
|
||||
| BuiltinFunction::Sin
|
||||
| BuiltinFunction::Tan
|
||||
| BuiltinFunction::ACos
|
||||
| BuiltinFunction::ASin
|
||||
| BuiltinFunction::Log
|
||||
| BuiltinFunction::Pow
|
||||
| BuiltinFunction::ATan => true,
|
||||
BuiltinFunction::SetFocusItem => false,
|
||||
BuiltinFunction::ShowPopupWindow => false,
|
||||
BuiltinFunction::StringToFloat | BuiltinFunction::StringIsFloat => true,
|
||||
BuiltinFunction::ColorBrighter | BuiltinFunction::ColorDarker => true,
|
||||
BuiltinFunction::ImageSize => true,
|
||||
BuiltinFunction::ArrayLength => true,
|
||||
BuiltinFunction::Rgb => true,
|
||||
BuiltinFunction::ImplicitLayoutInfo(_) => true,
|
||||
BuiltinFunction::RegisterCustomFontByPath
|
||||
| BuiltinFunction::RegisterCustomFontByMemory
|
||||
| BuiltinFunction::RegisterBitmapFont => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
|
@ -344,13 +381,13 @@ pub enum Expression {
|
|||
/// Reference to the callback `<name>` in the `<element>`
|
||||
///
|
||||
/// Note: if we are to separate expression and statement, we probably do not need to have callback reference within expressions
|
||||
CallbackReference(NamedReference),
|
||||
CallbackReference(NamedReference, Option<NodeOrToken>),
|
||||
|
||||
/// Reference to the property
|
||||
PropertyReference(NamedReference),
|
||||
|
||||
/// Reference to a function
|
||||
FunctionReference(NamedReference),
|
||||
FunctionReference(NamedReference, Option<NodeOrToken>),
|
||||
|
||||
/// Reference to a function built into the run-time, implemented natively
|
||||
BuiltinFunctionReference(BuiltinFunction, Option<SourceLocation>),
|
||||
|
|
@ -436,12 +473,13 @@ pub enum Expression {
|
|||
source_location: Option<SourceLocation>,
|
||||
},
|
||||
|
||||
/// A SelfAssignment or an Assignment. When op is '=' this is a signal assignment.
|
||||
/// A SelfAssignment or an Assignment. When op is '=' this is a simple assignment.
|
||||
SelfAssignment {
|
||||
lhs: Box<Expression>,
|
||||
rhs: Box<Expression>,
|
||||
/// '+', '-', '/', '*', or '='
|
||||
op: char,
|
||||
node: Option<NodeOrToken>,
|
||||
},
|
||||
|
||||
BinaryExpression {
|
||||
|
|
@ -518,8 +556,8 @@ impl Expression {
|
|||
Expression::StringLiteral(_) => Type::String,
|
||||
Expression::NumberLiteral(_, unit) => unit.ty(),
|
||||
Expression::BoolLiteral(_) => Type::Bool,
|
||||
Expression::CallbackReference(nr) => nr.ty(),
|
||||
Expression::FunctionReference(nr) => nr.ty(),
|
||||
Expression::CallbackReference(nr, _) => nr.ty(),
|
||||
Expression::FunctionReference(nr, _) => nr.ty(),
|
||||
Expression::PropertyReference(nr) => nr.ty(),
|
||||
Expression::BuiltinFunctionReference(funcref, _) => funcref.ty(),
|
||||
Expression::MemberFunction { member, .. } => member.ty(),
|
||||
|
|
@ -865,9 +903,9 @@ impl Expression {
|
|||
Expression::NumberLiteral(_, _) => true,
|
||||
Expression::BoolLiteral(_) => true,
|
||||
Expression::CallbackReference { .. } => false,
|
||||
Expression::FunctionReference(nr) => nr.is_constant(),
|
||||
Expression::FunctionReference(nr, _) => nr.is_constant(),
|
||||
Expression::PropertyReference(nr) => nr.is_constant(),
|
||||
Expression::BuiltinFunctionReference(func, _) => func.is_pure(),
|
||||
Expression::BuiltinFunctionReference(func, _) => func.is_const(),
|
||||
Expression::MemberFunction { .. } => false,
|
||||
Expression::ElementReference(_) => false,
|
||||
Expression::RepeaterIndexReference { .. } => false,
|
||||
|
|
@ -1369,9 +1407,9 @@ pub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std
|
|||
Expression::StringLiteral(s) => write!(f, "{:?}", s),
|
||||
Expression::NumberLiteral(vl, unit) => write!(f, "{}{}", vl, unit),
|
||||
Expression::BoolLiteral(b) => write!(f, "{:?}", b),
|
||||
Expression::CallbackReference(a) => write!(f, "{:?}", a),
|
||||
Expression::CallbackReference(a, _) => write!(f, "{:?}", a),
|
||||
Expression::PropertyReference(a) => write!(f, "{:?}", a),
|
||||
Expression::FunctionReference(a) => write!(f, "{:?}", a),
|
||||
Expression::FunctionReference(a, _) => write!(f, "{:?}", a),
|
||||
Expression::BuiltinFunctionReference(a, _) => write!(f, "{:?}", a),
|
||||
Expression::MemberFunction { base, base_node: _, member } => {
|
||||
pretty_print(f, base)?;
|
||||
|
|
@ -1425,7 +1463,7 @@ pub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std
|
|||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
Expression::SelfAssignment { lhs, rhs, op } => {
|
||||
Expression::SelfAssignment { lhs, rhs, op, .. } => {
|
||||
pretty_print(f, lhs)?;
|
||||
write!(f, " {}= ", if *op == '=' { ' ' } else { *op })?;
|
||||
pretty_print(f, rhs)
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@ impl ElementType {
|
|||
resolved_name,
|
||||
property_type: Type::Invalid,
|
||||
property_visibility: PropertyVisibility::Private,
|
||||
declared_pure: None,
|
||||
is_local_to_component: false,
|
||||
}
|
||||
} else {
|
||||
|
|
@ -413,6 +414,7 @@ impl ElementType {
|
|||
resolved_name,
|
||||
property_type: p.ty.clone(),
|
||||
property_visibility: p.property_visibility,
|
||||
declared_pure: None,
|
||||
is_local_to_component: false,
|
||||
},
|
||||
}
|
||||
|
|
@ -429,6 +431,7 @@ impl ElementType {
|
|||
resolved_name,
|
||||
property_type,
|
||||
property_visibility: PropertyVisibility::InOut,
|
||||
declared_pure: None,
|
||||
is_local_to_component: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -436,6 +439,7 @@ impl ElementType {
|
|||
resolved_name: Cow::Borrowed(name),
|
||||
property_type: Type::Invalid,
|
||||
property_visibility: PropertyVisibility::Private,
|
||||
declared_pure: None,
|
||||
is_local_to_component: false,
|
||||
},
|
||||
}
|
||||
|
|
@ -690,6 +694,7 @@ pub struct PropertyLookupResult<'a> {
|
|||
pub resolved_name: std::borrow::Cow<'a, str>,
|
||||
pub property_type: Type,
|
||||
pub property_visibility: PropertyVisibility,
|
||||
pub declared_pure: Option<bool>,
|
||||
/// True if the property is part of the the current component (for visibility purposes)
|
||||
pub is_local_to_component: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,9 +68,9 @@ pub fn lower_expression(
|
|||
llr_Expression::NumberLiteral(unit.normalize(*n))
|
||||
}
|
||||
tree_Expression::BoolLiteral(b) => llr_Expression::BoolLiteral(*b),
|
||||
tree_Expression::CallbackReference(nr)
|
||||
tree_Expression::CallbackReference(nr, _)
|
||||
| tree_Expression::PropertyReference(nr)
|
||||
| tree_Expression::FunctionReference(nr) => {
|
||||
| tree_Expression::FunctionReference(nr, _) => {
|
||||
llr_Expression::PropertyReference(ctx.map_property_reference(nr))
|
||||
}
|
||||
tree_Expression::BuiltinFunctionReference(_, _) => panic!(),
|
||||
|
|
@ -120,17 +120,19 @@ pub fn lower_expression(
|
|||
let arguments = arguments.iter().map(|e| lower_expression(e, ctx)).collect::<_>();
|
||||
llr_Expression::BuiltinFunctionCall { function: *f, arguments }
|
||||
}
|
||||
tree_Expression::CallbackReference(nr) => {
|
||||
tree_Expression::CallbackReference(nr, _) => {
|
||||
let arguments = arguments.iter().map(|e| lower_expression(e, ctx)).collect::<_>();
|
||||
llr_Expression::CallBackCall { callback: ctx.map_property_reference(nr), arguments }
|
||||
}
|
||||
tree_Expression::FunctionReference(nr) => {
|
||||
tree_Expression::FunctionReference(nr, _) => {
|
||||
let arguments = arguments.iter().map(|e| lower_expression(e, ctx)).collect::<_>();
|
||||
llr_Expression::FunctionCall { function: ctx.map_property_reference(nr), arguments }
|
||||
}
|
||||
_ => panic!("not calling a function"),
|
||||
},
|
||||
tree_Expression::SelfAssignment { lhs, rhs, op } => lower_assignment(lhs, rhs, *op, ctx),
|
||||
tree_Expression::SelfAssignment { lhs, rhs, op, .. } => {
|
||||
lower_assignment(lhs, rhs, *op, ctx)
|
||||
}
|
||||
tree_Expression::BinaryExpression { lhs, rhs, op } => llr_Expression::BinaryExpression {
|
||||
lhs: Box::new(lower_expression(lhs, ctx)),
|
||||
rhs: Box::new(lower_expression(rhs, ctx)),
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ impl LookupObject for InScopeLookup {
|
|||
let e = expression_from_reference(
|
||||
NamedReference::new(elem, name),
|
||||
&prop.property_type,
|
||||
&ctx.current_token,
|
||||
);
|
||||
if let Some(r) = f.borrow_mut()(name, e.into()) {
|
||||
return Some(r);
|
||||
|
|
@ -364,8 +365,12 @@ impl LookupObject for InScopeLookup {
|
|||
|elem| elem.lookup(ctx, name),
|
||||
|elem| {
|
||||
elem.borrow().property_declarations.get(name).map(|prop| {
|
||||
expression_from_reference(NamedReference::new(elem, name), &prop.property_type)
|
||||
.into()
|
||||
expression_from_reference(
|
||||
NamedReference::new(elem, name),
|
||||
&prop.property_type,
|
||||
&ctx.current_token,
|
||||
)
|
||||
.into()
|
||||
})
|
||||
},
|
||||
)
|
||||
|
|
@ -375,24 +380,33 @@ impl LookupObject for InScopeLookup {
|
|||
impl LookupObject for ElementRc {
|
||||
fn for_each_entry<R>(
|
||||
&self,
|
||||
_ctx: &LookupCtx,
|
||||
ctx: &LookupCtx,
|
||||
f: &mut impl FnMut(&str, LookupResult) -> Option<R>,
|
||||
) -> Option<R> {
|
||||
for (name, prop) in &self.borrow().property_declarations {
|
||||
let e = expression_from_reference(NamedReference::new(self, name), &prop.property_type);
|
||||
let e = expression_from_reference(
|
||||
NamedReference::new(self, name),
|
||||
&prop.property_type,
|
||||
&ctx.current_token,
|
||||
);
|
||||
if let Some(r) = f(name, e.into()) {
|
||||
return Some(r);
|
||||
}
|
||||
}
|
||||
let list = self.borrow().base_type.property_list();
|
||||
for (name, ty) in list {
|
||||
let e = expression_from_reference(NamedReference::new(self, &name), &ty);
|
||||
let e = expression_from_reference(
|
||||
NamedReference::new(self, &name),
|
||||
&ty,
|
||||
&ctx.current_token,
|
||||
);
|
||||
if let Some(r) = f(&name, e.into()) {
|
||||
return Some(r);
|
||||
}
|
||||
}
|
||||
for (name, ty) in crate::typeregister::reserved_properties() {
|
||||
let e = expression_from_reference(NamedReference::new(self, name), &ty);
|
||||
let e =
|
||||
expression_from_reference(NamedReference::new(self, name), &ty, &ctx.current_token);
|
||||
if let Some(r) = f(name, e.into()) {
|
||||
return Some(r);
|
||||
}
|
||||
|
|
@ -400,7 +414,7 @@ impl LookupObject for ElementRc {
|
|||
None
|
||||
}
|
||||
|
||||
fn lookup(&self, _ctx: &LookupCtx, name: &str) -> Option<LookupResult> {
|
||||
fn lookup(&self, ctx: &LookupCtx, name: &str) -> Option<LookupResult> {
|
||||
let lookup_result = self.borrow().lookup_property(name);
|
||||
if lookup_result.property_type != Type::Invalid
|
||||
&& (lookup_result.is_local_to_component
|
||||
|
|
@ -410,6 +424,7 @@ impl LookupObject for ElementRc {
|
|||
expression: expression_from_reference(
|
||||
NamedReference::new(self, &lookup_result.resolved_name),
|
||||
&lookup_result.property_type,
|
||||
&ctx.current_token,
|
||||
),
|
||||
deprecated: (lookup_result.resolved_name != name)
|
||||
.then(|| lookup_result.resolved_name.to_string()),
|
||||
|
|
@ -420,10 +435,14 @@ impl LookupObject for ElementRc {
|
|||
}
|
||||
}
|
||||
|
||||
fn expression_from_reference(n: NamedReference, ty: &Type) -> Expression {
|
||||
fn expression_from_reference(
|
||||
n: NamedReference,
|
||||
ty: &Type,
|
||||
node: &Option<NodeOrToken>,
|
||||
) -> Expression {
|
||||
match ty {
|
||||
Type::Callback { .. } => Expression::CallbackReference(n),
|
||||
Type::Function { .. } => Expression::FunctionReference(n),
|
||||
Type::Callback { .. } => Expression::CallbackReference(n, node.clone()),
|
||||
Type::Function { .. } => Expression::FunctionReference(n, node.clone()),
|
||||
_ => Expression::PropertyReference(n),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -360,6 +360,8 @@ pub struct PropertyDeclaration {
|
|||
/// Public API property exposed as an alias: it shouldn't be generated but instead forward to the alias.
|
||||
pub is_alias: Option<NamedReference>,
|
||||
pub visibility: PropertyVisibility,
|
||||
/// For function or callback: whether it is declared as `pure` (None for private function for which this has to be deduced)
|
||||
pub pure: Option<bool>,
|
||||
}
|
||||
|
||||
impl PropertyDeclaration {
|
||||
|
|
@ -869,6 +871,10 @@ impl Element {
|
|||
let name =
|
||||
unwrap_or_continue!(parser::identifier_text(&sig_decl.DeclaredIdentifier()); diag);
|
||||
|
||||
let pure = Some(
|
||||
sig_decl.child_token(SyntaxKind::Identifier).map_or(false, |t| t.text() == "pure"),
|
||||
);
|
||||
|
||||
if let Some(csn) = sig_decl.TwoWayBinding() {
|
||||
r.bindings
|
||||
.insert(name.clone(), BindingExpression::new_uncompiled(csn.into()).into());
|
||||
|
|
@ -878,6 +884,7 @@ impl Element {
|
|||
property_type: Type::InferredCallback,
|
||||
node: Some(sig_decl.into()),
|
||||
visibility: PropertyVisibility::InOut,
|
||||
pure,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
|
@ -924,6 +931,7 @@ impl Element {
|
|||
property_type: Type::Callback { return_type, args },
|
||||
node: Some(sig_decl.into()),
|
||||
visibility: PropertyVisibility::InOut,
|
||||
pure,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
|
@ -979,18 +987,29 @@ impl Element {
|
|||
assert!(diag.has_error());
|
||||
}
|
||||
|
||||
let public =
|
||||
func.child_token(SyntaxKind::Identifier).map_or(false, |t| t.text() == "public");
|
||||
let mut visibility = PropertyVisibility::Private;
|
||||
let mut pure = None;
|
||||
for token in func.children_with_tokens() {
|
||||
if token.kind() != SyntaxKind::Identifier {
|
||||
continue;
|
||||
}
|
||||
match token.as_token().unwrap().text() {
|
||||
"pure" => pure = Some(true),
|
||||
"public" => {
|
||||
visibility = PropertyVisibility::Public;
|
||||
pure = pure.or_else(|| Some(false));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
r.property_declarations.insert(
|
||||
name,
|
||||
PropertyDeclaration {
|
||||
property_type: Type::Function { return_type, args },
|
||||
node: Some(func.into()),
|
||||
visibility: if public {
|
||||
PropertyVisibility::Public
|
||||
} else {
|
||||
PropertyVisibility::Private
|
||||
},
|
||||
visibility,
|
||||
pure,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
|
@ -1334,6 +1353,7 @@ impl Element {
|
|||
resolved_name: name.into(),
|
||||
property_type: p.property_type.clone(),
|
||||
property_visibility: p.visibility,
|
||||
declared_pure: p.pure,
|
||||
is_local_to_component: true,
|
||||
},
|
||||
)
|
||||
|
|
@ -1891,8 +1911,8 @@ pub fn visit_named_references_in_expression(
|
|||
expr.visit_mut(|sub| visit_named_references_in_expression(sub, vis));
|
||||
match expr {
|
||||
Expression::PropertyReference(r)
|
||||
| Expression::CallbackReference(r)
|
||||
| Expression::FunctionReference(r) => vis(r),
|
||||
| Expression::CallbackReference(r, _)
|
||||
| Expression::FunctionReference(r, _) => vis(r),
|
||||
Expression::LayoutCacheAccess { layout_cache_prop, .. } => vis(layout_cache_prop),
|
||||
Expression::SolveLayout(l, _) => l.visit_named_references(vis),
|
||||
Expression::ComputeLayoutInfo(l, _) => l.visit_named_references(vis),
|
||||
|
|
|
|||
|
|
@ -55,14 +55,18 @@ pub fn parse_element_content(p: &mut impl Parser) {
|
|||
SyntaxKind::Identifier if p.peek().as_str() == "for" => {
|
||||
parse_repeated_element(&mut *p);
|
||||
}
|
||||
SyntaxKind::Identifier if p.peek().as_str() == "callback" => {
|
||||
SyntaxKind::Identifier
|
||||
if p.peek().as_str() == "callback"
|
||||
|| (p.peek().as_str() == "pure" && p.nth(1).as_str() == "callback") =>
|
||||
{
|
||||
parse_callback_declaration(&mut *p);
|
||||
}
|
||||
SyntaxKind::Identifier if p.peek().as_str() == "function" => {
|
||||
parse_function(&mut *p);
|
||||
}
|
||||
SyntaxKind::Identifier
|
||||
if p.peek().as_str() == "public" && p.nth(1).as_str() == "function" =>
|
||||
if p.peek().as_str() == "function"
|
||||
|| (matches!(p.peek().as_str(), "public" | "pure")
|
||||
&& p.nth(1).as_str() == "function")
|
||||
|| (matches!(p.nth(1).as_str(), "public" | "pure")
|
||||
&& p.nth(2).as_str() == "function") =>
|
||||
{
|
||||
parse_function(&mut *p);
|
||||
}
|
||||
|
|
@ -288,7 +292,7 @@ fn parse_two_way_binding(p: &mut impl Parser) {
|
|||
/// callback foobar;
|
||||
/// callback my_callback();
|
||||
/// callback foo(int, string);
|
||||
/// callback one_arg({ a: string, b: string});
|
||||
/// pure callback one_arg({ a: string, b: string});
|
||||
/// callback end_coma(a, b, c,);
|
||||
/// callback with_return(a, b) -> int;
|
||||
/// callback with_return2({a: string}) -> { a: string };
|
||||
|
|
@ -296,8 +300,11 @@ fn parse_two_way_binding(p: &mut impl Parser) {
|
|||
/// ```
|
||||
/// Must consume at least one token
|
||||
fn parse_callback_declaration(p: &mut impl Parser) {
|
||||
debug_assert_eq!(p.peek().as_str(), "callback");
|
||||
let mut p = p.start_node(SyntaxKind::CallbackDeclaration);
|
||||
if p.peek().as_str() == "pure" {
|
||||
p.consume();
|
||||
}
|
||||
debug_assert_eq!(p.peek().as_str(), "callback");
|
||||
p.expect(SyntaxKind::Identifier); // "callback"
|
||||
{
|
||||
let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
|
||||
|
|
@ -572,7 +579,22 @@ fn parse_transition_inner(p: &mut impl Parser) -> bool {
|
|||
fn parse_function(p: &mut impl Parser) {
|
||||
let mut p = p.start_node(SyntaxKind::Function);
|
||||
if p.peek().as_str() == "public" {
|
||||
p.consume()
|
||||
p.consume();
|
||||
if p.peek().as_str() == "pure" {
|
||||
p.consume()
|
||||
}
|
||||
} else if p.peek().as_str() == "pure" {
|
||||
p.consume();
|
||||
if p.peek().as_str() == "public" {
|
||||
p.consume()
|
||||
}
|
||||
}
|
||||
if p.peek().as_str() != "function" {
|
||||
p.error("Unexpected identifier");
|
||||
p.consume();
|
||||
while p.peek().kind == SyntaxKind::Identifier && p.peek().as_str() != "function" {
|
||||
p.consume();
|
||||
}
|
||||
}
|
||||
debug_assert_eq!(p.peek().as_str(), "function");
|
||||
p.expect(SyntaxKind::Identifier); // "function"
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ mod lower_tabwidget;
|
|||
mod materialize_fake_properties;
|
||||
mod move_declarations;
|
||||
mod optimize_useless_rectangles;
|
||||
mod purity_check;
|
||||
mod remove_aliases;
|
||||
mod remove_unused_properties;
|
||||
mod repeater_component;
|
||||
|
|
@ -74,11 +75,7 @@ pub async fn run_passes(
|
|||
|
||||
let global_type_registry = type_loader.global_type_registry.clone();
|
||||
let root_component = &doc.root_component;
|
||||
infer_aliases_types::resolve_aliases(doc, diag);
|
||||
resolving::resolve_expressions(doc, type_loader, diag);
|
||||
check_expressions::check_expressions(doc, diag);
|
||||
check_rotation::check_rotation(doc, diag);
|
||||
unique_id::check_unique_id(doc, diag);
|
||||
run_import_passes(doc, type_loader, diag);
|
||||
check_public_api::check_public_api(doc, diag);
|
||||
|
||||
collect_subcomponents::collect_subcomponents(root_component);
|
||||
|
|
@ -268,6 +265,7 @@ pub fn run_import_passes(
|
|||
infer_aliases_types::resolve_aliases(doc, diag);
|
||||
resolving::resolve_expressions(doc, type_loader, diag);
|
||||
check_expressions::check_expressions(doc, diag);
|
||||
purity_check::purity_check(doc, diag);
|
||||
check_rotation::check_rotation(doc, diag);
|
||||
unique_id::check_unique_id(doc, diag);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,8 +335,8 @@ fn recurse_expression(expr: &Expression, vis: &mut impl FnMut(&PropertyPath)) {
|
|||
expr.visit(|sub| recurse_expression(sub, vis));
|
||||
match expr {
|
||||
Expression::PropertyReference(r)
|
||||
| Expression::CallbackReference(r)
|
||||
| Expression::FunctionReference(r) => vis(&r.clone().into()),
|
||||
| Expression::CallbackReference(r, _)
|
||||
| Expression::FunctionReference(r, _) => vis(&r.clone().into()),
|
||||
Expression::LayoutCacheAccess { layout_cache_prop, .. } => {
|
||||
vis(&layout_cache_prop.clone().into())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -497,6 +497,7 @@ fn lower_dialog_layout(
|
|||
"clicked",
|
||||
)),
|
||||
visibility: PropertyVisibility::InOut,
|
||||
pure: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,9 +215,9 @@ fn expression_for_property(element: &ElementRc, name: &str) -> ExpressionForProp
|
|||
// Check that the expresison is valid in the new scope
|
||||
let mut has_invalid = false;
|
||||
e.expression.visit_recursive(&mut |ex| match ex {
|
||||
Expression::CallbackReference(nr)
|
||||
Expression::CallbackReference(nr, _)
|
||||
| Expression::PropertyReference(nr)
|
||||
| Expression::FunctionReference(nr) => {
|
||||
| Expression::FunctionReference(nr, _) => {
|
||||
let e = nr.element();
|
||||
if !Rc::ptr_eq(&e, &element)
|
||||
&& Weak::ptr_eq(
|
||||
|
|
|
|||
94
internal/compiler/passes/purity_check.rs
Normal file
94
internal/compiler/passes/purity_check.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
use crate::diagnostics::BuildDiagnostics;
|
||||
use crate::expression_tree::Expression;
|
||||
|
||||
/// Check that pure expression only call pure functions
|
||||
pub fn purity_check(doc: &crate::object_tree::Document, diag: &mut BuildDiagnostics) {
|
||||
for component in &doc.inner_components {
|
||||
crate::object_tree::recurse_elem_including_sub_components_no_borrow(
|
||||
component,
|
||||
&(),
|
||||
&mut |elem, &()| {
|
||||
crate::object_tree::visit_element_expressions(elem, |expr, name, _| {
|
||||
if let Some(name) = name {
|
||||
let lookup = elem.borrow().lookup_property(name);
|
||||
if lookup.declared_pure.unwrap_or(false)
|
||||
|| lookup.property_type.is_property_type()
|
||||
{
|
||||
ensure_pure(expr, Some(diag));
|
||||
}
|
||||
} else {
|
||||
// model expression must be pure
|
||||
ensure_pure(expr, Some(diag));
|
||||
};
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_pure(expr: &Expression, mut diag: Option<&mut BuildDiagnostics>) -> bool {
|
||||
let mut r = true;
|
||||
expr.visit_recursive(&mut |e| match e {
|
||||
Expression::CallbackReference(nr, node) => {
|
||||
if !nr.element().borrow().lookup_property(nr.name()).declared_pure.unwrap_or(false) {
|
||||
if let Some(diag) = diag.as_deref_mut() {
|
||||
diag.push_error(format!("Cannot call impure callback '{}'", nr.name()), node);
|
||||
}
|
||||
r = false;
|
||||
}
|
||||
}
|
||||
Expression::FunctionReference(nr, node) => {
|
||||
match nr.element().borrow().lookup_property(nr.name()).declared_pure {
|
||||
Some(true) => return,
|
||||
Some(false) => {
|
||||
if let Some(diag) = diag.as_deref_mut() {
|
||||
diag.push_error(
|
||||
format!("Cannot call impure function '{}'", nr.name(),),
|
||||
node,
|
||||
);
|
||||
}
|
||||
r = false;
|
||||
}
|
||||
None => {
|
||||
if !ensure_pure(
|
||||
&nr.element()
|
||||
.borrow()
|
||||
.bindings
|
||||
.get(nr.name())
|
||||
.expect("private function must be local and defined")
|
||||
.borrow()
|
||||
.expression,
|
||||
None,
|
||||
) {
|
||||
if let Some(diag) = diag.as_deref_mut() {
|
||||
diag.push_error(
|
||||
format!("Cannot call impure function '{}'", nr.name(),),
|
||||
node,
|
||||
);
|
||||
}
|
||||
r = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::BuiltinFunctionReference(func, node) => {
|
||||
if !func.is_pure() {
|
||||
if let Some(diag) = diag.as_deref_mut() {
|
||||
diag.push_error("Cannot call impure function".into(), node);
|
||||
}
|
||||
r = false;
|
||||
}
|
||||
}
|
||||
Expression::SelfAssignment { node, .. } => {
|
||||
if let Some(diag) = diag.as_deref_mut() {
|
||||
diag.push_error("Cannot assign in a pure context".into(), node);
|
||||
}
|
||||
r = false;
|
||||
}
|
||||
_ => (),
|
||||
});
|
||||
r
|
||||
}
|
||||
|
|
@ -746,6 +746,7 @@ impl Expression {
|
|||
lhs: Box::new(lhs),
|
||||
rhs: Box::new(rhs.maybe_convert_to(expected_ty, &rhs_n, ctx.diag)),
|
||||
op,
|
||||
node: Some(NodeOrToken::Node(node.into())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1063,7 +1064,10 @@ fn continue_lookup_within_element(
|
|||
if let Some(x) = it.next() {
|
||||
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
|
||||
}
|
||||
Expression::CallbackReference(NamedReference::new(elem, &lookup_result.resolved_name))
|
||||
Expression::CallbackReference(
|
||||
NamedReference::new(elem, &lookup_result.resolved_name),
|
||||
Some(NodeOrToken::Token(second)),
|
||||
)
|
||||
} else if matches!(lookup_result.property_type, Type::Function { .. }) {
|
||||
if !lookup_result.is_local_to_component
|
||||
&& lookup_result.property_visibility == PropertyVisibility::Private
|
||||
|
|
@ -1083,7 +1087,10 @@ fn continue_lookup_within_element(
|
|||
.into(),
|
||||
}
|
||||
} else {
|
||||
Expression::FunctionReference(NamedReference::new(elem, &lookup_result.resolved_name))
|
||||
Expression::FunctionReference(
|
||||
NamedReference::new(elem, &lookup_result.resolved_name),
|
||||
Some(NodeOrToken::Token(second)),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let mut err = |extra: &str| {
|
||||
|
|
@ -1295,7 +1302,7 @@ pub fn resolve_two_way_binding(
|
|||
}
|
||||
Some(n)
|
||||
}
|
||||
Expression::CallbackReference(n) => {
|
||||
Expression::CallbackReference(n, _) => {
|
||||
if ctx.property_type != Type::InferredCallback && ty != ctx.property_type {
|
||||
ctx.diag.push_error("Cannot bind to a callback".into(), &node);
|
||||
None
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Compo1 := Rectangle {
|
|||
|
||||
property <int> a : aa();
|
||||
// ^error{The binding for the property 'a' is part of a binding loop}
|
||||
callback aa() -> int;
|
||||
pure callback aa() -> int;
|
||||
|
||||
function factorial(n: int) -> int {
|
||||
// ^error{The binding for the property 'factorial' is part of a binding loop}
|
||||
|
|
@ -14,7 +14,7 @@ Compo1 := Rectangle {
|
|||
|
||||
|
||||
property <int> b;
|
||||
public function bb() -> int { return b; }
|
||||
public pure function bb() -> int { return b; }
|
||||
// ^error{The binding for the property 'bb' is part of a binding loop}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,4 +15,5 @@ X := Rectangle {
|
|||
x: edit.focus;
|
||||
// ^error{Cannot convert function\(element ref\) -> void to length}
|
||||
// ^^error{'edit.focus' must be called. Did you forgot the '\(\)'\?}
|
||||
// ^^^error{Cannot call impure function}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
|
||||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
component Foo {
|
||||
property <int> prop;
|
||||
callback c1;
|
||||
pure callback c2;
|
||||
|
||||
function f1() {
|
||||
prop = 1;
|
||||
}
|
||||
function f2() -> int { 42 }
|
||||
|
||||
pure function f3() {
|
||||
f2();
|
||||
f1();
|
||||
// ^error{Cannot call impure function 'f1'}
|
||||
|
||||
prop /= 5;
|
||||
// ^error{Cannot assign in a pure context}
|
||||
}
|
||||
public function f4() {}
|
||||
|
||||
|
||||
pure function f5() {
|
||||
f1();
|
||||
// ^error{Cannot call impure function 'f1'}
|
||||
f2(); // ok, private function auto-detected as pure
|
||||
f3();
|
||||
f4();
|
||||
// ^error{Cannot call impure function 'f4'}
|
||||
c1();
|
||||
// ^error{Cannot call impure callback 'c1'}
|
||||
c2();
|
||||
}
|
||||
|
||||
c1 => { f2() }
|
||||
c2 => {
|
||||
c1();
|
||||
// ^error{Cannot call impure callback 'c1'}
|
||||
}
|
||||
|
||||
|
||||
property <int> p1: f2();
|
||||
property <int> p2: {
|
||||
p1 = 42;
|
||||
// ^error{Cannot assign in a pure context}
|
||||
42
|
||||
};
|
||||
property <int> p3: {
|
||||
pw.show();
|
||||
// ^error{Cannot call impure function}
|
||||
fs.focus();
|
||||
// ^error{Cannot call impure function}
|
||||
42
|
||||
};
|
||||
|
||||
pw := PopupWindow {}
|
||||
fs := FocusScope {}
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +141,7 @@ pub fn reserved_property(name: &str) -> PropertyLookupResult {
|
|||
resolved_name: name.into(),
|
||||
is_local_to_component: false,
|
||||
property_visibility: crate::object_tree::PropertyVisibility::InOut,
|
||||
declared_pure: None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -156,6 +157,7 @@ pub fn reserved_property(name: &str) -> PropertyLookupResult {
|
|||
resolved_name: format!("{}-{}", pre, suf).into(),
|
||||
is_local_to_component: false,
|
||||
property_visibility: crate::object_tree::PropertyVisibility::InOut,
|
||||
declared_pure: None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -167,6 +169,7 @@ pub fn reserved_property(name: &str) -> PropertyLookupResult {
|
|||
property_type: Type::Invalid,
|
||||
is_local_to_component: false,
|
||||
property_visibility: crate::object_tree::PropertyVisibility::Private,
|
||||
declared_pure: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalCon
|
|||
v
|
||||
}
|
||||
Expression::FunctionCall { function, arguments, source_location: _ } => match &**function {
|
||||
Expression::FunctionReference(nr) => {
|
||||
Expression::FunctionReference(nr, _) => {
|
||||
let args = arguments.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>();
|
||||
generativity::make_guard!(guard);
|
||||
match enclosing_component_instance_for_element(&nr.element(), local_context.component_instance, guard) {
|
||||
|
|
@ -225,14 +225,14 @@ pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalCon
|
|||
},
|
||||
}
|
||||
}
|
||||
Expression::CallbackReference(nr) => {
|
||||
Expression::CallbackReference(nr, _) => {
|
||||
let args = arguments.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>();
|
||||
invoke_callback(local_context.component_instance, &nr.element(), nr.name(), &args).unwrap()
|
||||
}
|
||||
Expression::BuiltinFunctionReference(f, _) => call_builtin_function(*f, arguments, local_context),
|
||||
_ => panic!("call of something not a callback: {function:?}"),
|
||||
}
|
||||
Expression::SelfAssignment { lhs, rhs, op } => {
|
||||
Expression::SelfAssignment { lhs, rhs, op, .. } => {
|
||||
let rhs = eval_expression(&**rhs, local_context);
|
||||
eval_assignment(lhs, *op, rhs, local_context);
|
||||
Value::Void
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ pub(crate) fn add_highlight_items(doc: &Document) {
|
|||
expose_in_public_api: false,
|
||||
is_alias: None,
|
||||
visibility: PropertyVisibility::Input,
|
||||
pure: None,
|
||||
},
|
||||
);
|
||||
doc.root_component.root_element.borrow_mut().property_analysis.borrow_mut().insert(
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
Foo := Rectangle {
|
||||
callback hallo_alias <=> xxx.hallo;
|
||||
pure callback hallo_alias <=> xxx.hallo;
|
||||
callback clicked <=> are.clicked;
|
||||
xxx := Rectangle {
|
||||
callback hallo(int) -> int;
|
||||
pure callback hallo(int) -> int;
|
||||
hallo(a) => { return a + 88; }
|
||||
}
|
||||
|
||||
|
|
@ -14,8 +14,8 @@ Foo := Rectangle {
|
|||
|
||||
TestCase := Rectangle {
|
||||
|
||||
callback foo1_alias <=> foo1.hallo_alias;
|
||||
callback foo2_alias <=> foo2.hallo_alias;
|
||||
pure callback foo1_alias <=> foo1.hallo_alias;
|
||||
pure callback foo2_alias <=> foo2.hallo_alias;
|
||||
|
||||
callback foo1_clicked <=> foo1.clicked;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ global G := {
|
|||
}
|
||||
|
||||
SubCompo := Rectangle {
|
||||
public function hello() -> color { red }
|
||||
public pure function hello() -> color { red }
|
||||
}
|
||||
|
||||
TestCase := Rectangle {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
TestCase := Rectangle {
|
||||
callback test_func(int) -> int;
|
||||
callback test_func2(string, int) -> string;
|
||||
pure callback test_func(int) -> int;
|
||||
pure callback test_func2(string, int) -> string;
|
||||
test_func2(str, val) => { str + "=" + (val + some_value) }
|
||||
|
||||
property <int> test_prop: 4 + test_func(2);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ struct MyStruct := { x:int, y: int, }
|
|||
global InternalGlobal := {
|
||||
property <int> hello: 42;
|
||||
property <MyStruct> my_struct;
|
||||
callback sum(int, int)->int;
|
||||
pure callback sum(int, int)->int;
|
||||
}
|
||||
|
||||
export { InternalGlobal as PublicGlobal }
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
global Glo := {
|
||||
property <int> hello: 42;
|
||||
callback sum(int, int) -> int;
|
||||
callback mul(int, int) -> int;
|
||||
callback calculate_profit() -> int;
|
||||
pure callback sum(int, int) -> int;
|
||||
pure callback mul(int, int) -> int;
|
||||
pure callback calculate_profit() -> int;
|
||||
calculate_profit() => { return 1000; }
|
||||
}
|
||||
|
||||
|
|
@ -16,8 +16,8 @@ ExtraComp := Rectangle {
|
|||
|
||||
|
||||
TestCase := Window {
|
||||
callback sum <=> Glo.sum;
|
||||
callback mul <=> Glo.mul;
|
||||
pure callback sum <=> Glo.sum;
|
||||
pure callback mul <=> Glo.mul;
|
||||
|
||||
x := ExtraComp {}
|
||||
property<int> five: x.five;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
global G {
|
||||
callback is-center(length, length, length) -> bool;
|
||||
is-center(pos, size, parent) => {
|
||||
public pure function is-center(pos: length, size: length, parent: length) -> bool {
|
||||
return abs(pos / 1px - (parent - size) / 2px) < 0.001;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ TestCase := Rectangle {
|
|||
foo.b += 8 + obj_conversion2.b;
|
||||
}
|
||||
|
||||
callback return_object() -> { aa: { bb: int } };
|
||||
return_object => { return { aa: { bb: { cc: 42 }.cc } }; }
|
||||
function return_object() -> { aa: { bb: int } }
|
||||
{ return { aa: { bb: { cc: 42 }.cc } }; }
|
||||
property <bool> test: return_object().aa.bb == 42 && obj_binop_merge;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ TestCase := Rectangle {
|
|||
cb1(foo) => { return { b: foo.a.member+1 }; }
|
||||
|
||||
property<Foo2> xx;
|
||||
callback cb2(Foo2, Foo2)->Foo2;
|
||||
pure callback cb2(Foo2, Foo2)->Foo2;
|
||||
property<Foo2> xx2: cb2(xx, xx);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -453,8 +453,8 @@ fn completion_item_from_expression(str: &str, lookup_result: LookupResult) -> Co
|
|||
let mut c = CompletionItem::new_simple(str.to_string(), expression.ty().to_string());
|
||||
c.kind = match expression {
|
||||
Expression::BoolLiteral(_) => Some(CompletionItemKind::CONSTANT),
|
||||
Expression::CallbackReference(_) => Some(CompletionItemKind::METHOD),
|
||||
Expression::FunctionReference(_) => Some(CompletionItemKind::FUNCTION),
|
||||
Expression::CallbackReference(..) => Some(CompletionItemKind::METHOD),
|
||||
Expression::FunctionReference(..) => Some(CompletionItemKind::FUNCTION),
|
||||
Expression::PropertyReference(_) => Some(CompletionItemKind::PROPERTY),
|
||||
Expression::BuiltinFunctionReference(..) => Some(CompletionItemKind::FUNCTION),
|
||||
Expression::BuiltinMacroReference(..) => Some(CompletionItemKind::FUNCTION),
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@ pub fn goto_definition(
|
|||
} => e.upgrade()?.borrow().node.clone()?.into(),
|
||||
LookupResult::Expression {
|
||||
expression:
|
||||
Expression::CallbackReference(nr)
|
||||
Expression::CallbackReference(nr, _)
|
||||
| Expression::PropertyReference(nr)
|
||||
| Expression::FunctionReference(nr),
|
||||
| Expression::FunctionReference(nr, _),
|
||||
..
|
||||
} => {
|
||||
let mut el = nr.element();
|
||||
|
|
|
|||
|
|
@ -127,8 +127,8 @@ fn fully_qualify_property_access(
|
|||
Some(LookupResult::Expression {
|
||||
expression:
|
||||
Expression::PropertyReference(nr)
|
||||
| Expression::CallbackReference(nr)
|
||||
| Expression::FunctionReference(nr),
|
||||
| Expression::CallbackReference(nr, _)
|
||||
| Expression::FunctionReference(nr, _),
|
||||
..
|
||||
}) => {
|
||||
if let Some(new_name) = state.lookup_change.property_mappings.get(&nr) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue