Skip to content

Commit 75058cb

Browse files
authored
Compiler: Remove Struct::rust_attributes and make it an error if @rust-attr(...) doesn't lex (#10118)
The `rust_attributes` in langtype::Struct is a bit wierd as it is only used for rust code generation, yet is stored in every Struct. Instead, read the `node` while doing code generation like we do in C++. The previous code was ignoring the error lexing the code in the attribute, and now we add a compile_error!
1 parent 9257fd2 commit 75058cb

File tree

14 files changed

+65
-71
lines changed

14 files changed

+65
-71
lines changed

api/rs/slint/compile_fail_tests.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,30 @@ mod x {
2626
#[cfg(doctest)]
2727
const basic: u32 = 0;
2828

29+
/**
30+
Test that invalid rust-attr are compilation error
31+
32+
This should result in a `compile_error!("Error parsing @rust-attr for struct 'Foo' declared at tests/invalid_rust_attr.slint:4:12"`
33+
```compile_fail
34+
use slint::*;
35+
slint!{
36+
export { Foo } from "tests/invalid_rust_attr.slint";
37+
export component Hello inherits Window { }
38+
}
39+
```
40+
41+
But Foo is not used/generated, then we do not detect the error
42+
(Having the test here to test that the previous test would otherwise work, but it would also be ok to detect the error and make it an actual slint compile error)
43+
```
44+
use slint::*;
45+
slint!{
46+
import { Foo } from "tests/invalid_rust_attr.slint";
47+
export component Hello inherits Window { }
48+
}
49+
```
50+
*/
51+
const INVALID_RUST_ATTR: () = ();
52+
2953
#[cfg(doctest)]
3054
#[doc = include_str!("README.md")]
3155
const CHECK_README_EXAMPLES: () = ();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright © SixtyFPS GmbH <[email protected]>
2+
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3+
4+
@rust-attr("Doesn't Lex in rust \{"🦞"}")
5+
export struct Foo { int: int }

internal/compiler/diagnostics.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,17 @@ impl std::fmt::Display for Diagnostic {
324324
}
325325
}
326326

327+
impl std::fmt::Display for SourceLocation {
328+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
329+
if let Some(sf) = &self.source_file {
330+
let (line, col) = sf.line_column(self.span.offset, ByteFormat::Utf8);
331+
write!(f, "{}:{line}:{col}", sf.path.display())
332+
} else {
333+
write!(f, "<unknown>")
334+
}
335+
}
336+
}
337+
327338
pub fn diagnostic_line_column_with_format(
328339
diagnostic: &Diagnostic,
329340
format: ByteFormat,

internal/compiler/expression_tree.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,6 @@ declare_builtin_function_types!(
218218
])
219219
.collect(),
220220
name: BuiltinPublicStruct::Color.into(),
221-
rust_attributes: None,
222221
})),
223222
ColorHsvaStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {
224223
fields: IntoIterator::into_iter([
@@ -229,7 +228,6 @@ declare_builtin_function_types!(
229228
])
230229
.collect(),
231230
name: BuiltinPublicStruct::Color.into(),
232-
rust_attributes: None,
233231
})),
234232
ColorBrighter: (Type::Brush, Type::Float32) -> Type::Brush,
235233
ColorDarker: (Type::Brush, Type::Float32) -> Type::Brush,
@@ -243,7 +241,6 @@ declare_builtin_function_types!(
243241
])
244242
.collect(),
245243
name: crate::langtype::BuiltinPrivateStruct::Size.into(),
246-
rust_attributes: None,
247244
})),
248245
ArrayLength: (Type::Model) -> Type::Int32,
249246
Rgb: (Type::Int32, Type::Int32, Type::Int32, Type::Float32) -> Type::Color,

internal/compiler/generator/rust.rs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -280,15 +280,8 @@ pub fn generate_types(used_types: &[Type]) -> (Vec<Ident>, TokenStream) {
280280
.iter()
281281
.filter_map(|ty| match ty {
282282
Type::Struct(s) => match s.as_ref() {
283-
Struct { fields, name: StructName::User { name, node }, rust_attributes } => {
284-
Some((
285-
ident(name),
286-
generate_struct(
287-
&StructName::User { name: name.clone(), node: node.clone() },
288-
fields,
289-
rust_attributes,
290-
),
291-
))
283+
Struct { fields, name: struct_name @ StructName::User { name, .. } } => {
284+
Some((ident(name), generate_struct(struct_name, fields)))
292285
}
293286
_ => None,
294287
},
@@ -519,25 +512,27 @@ fn generate_shared_globals(
519512
}
520513
}
521514

522-
fn generate_struct(
523-
name: &StructName,
524-
fields: &BTreeMap<SmolStr, Type>,
525-
rust_attributes: &Option<Vec<SmolStr>>,
526-
) -> TokenStream {
515+
fn generate_struct(name: &StructName, fields: &BTreeMap<SmolStr, Type>) -> TokenStream {
527516
let component_id = struct_name_to_tokens(&name).unwrap();
528517
let (declared_property_vars, declared_property_types): (Vec<_>, Vec<_>) =
529518
fields.iter().map(|(name, ty)| (ident(name), rust_primitive_type(ty).unwrap())).unzip();
530519

531-
let attributes = if let Some(feature) = rust_attributes {
532-
let attr =
533-
feature.iter().map(|f| match TokenStream::from_str(format!(r#"#[{f}]"#).as_str()) {
534-
Ok(eval) => eval,
535-
Err(_) => quote! {},
536-
});
537-
quote! { #(#attr)* }
538-
} else {
539-
quote! {}
540-
};
520+
let StructName::User { name, node } = name else { unreachable!("generating non-user struct") };
521+
522+
let attributes = node
523+
.parent()
524+
.and_then(crate::parser::syntax_nodes::StructDeclaration::new)
525+
.and_then(|d| d.AtRustAttr())
526+
.map(|n| match TokenStream::from_str(&n.text().to_string()) {
527+
Ok(t) => quote!(#[#t]),
528+
Err(_) => {
529+
let source_location = crate::diagnostics::Spanned::to_source_location(&n);
530+
let error = format!(
531+
"Error parsing @rust-attr for struct '{name}' declared at {source_location}"
532+
);
533+
quote!(compile_error!(#error);)
534+
}
535+
});
541536

542537
quote! {
543538
#attributes

internal/compiler/langtype.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -931,8 +931,6 @@ impl From<BuiltinPublicStruct> for StructName {
931931
pub struct Struct {
932932
pub fields: BTreeMap<SmolStr, Type>,
933933
pub name: StructName,
934-
/// derived
935-
pub rust_attributes: Option<Vec<SmolStr>>,
936934
}
937935

938936
impl Struct {

internal/compiler/llr/lower_expression.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,6 @@ pub fn lower_animation(a: &PropertyAnimation, ctx: &mut ExpressionLoweringCtx<'_
527527
Rc::new(Struct {
528528
fields: animation_fields().collect(),
529529
name: BuiltinPrivateStruct::PropertyAnimation.into(),
530-
rust_attributes: None,
531530
})
532531
}
533532

@@ -564,7 +563,6 @@ pub fn lower_animation(a: &PropertyAnimation, ctx: &mut ExpressionLoweringCtx<'_
564563
])
565564
.collect(),
566565
name: StructName::None,
567-
rust_attributes: None,
568566
}),
569567
values: IntoIterator::into_iter([
570568
(SmolStr::new_static("0"), get_anim),
@@ -872,7 +870,6 @@ pub(super) fn grid_layout_cell_data_ty() -> Type {
872870
])
873871
.collect(),
874872
name: BuiltinPrivateStruct::GridLayoutCellData.into(),
875-
rust_attributes: None,
876873
}))
877874
}
878875

@@ -994,7 +991,6 @@ fn compile_path(
994991
.clone()
995992
.expect("path elements should have a native_type"),
996993
),
997-
rust_attributes: None,
998994
});
999995

1000996
llr_Expression::Struct {
@@ -1045,7 +1041,6 @@ fn compile_path(
10451041
])
10461042
.collect(),
10471043
name: StructName::None,
1048-
rust_attributes: None,
10491044
}),
10501045
values: IntoIterator::into_iter([
10511046
(
@@ -1089,8 +1084,5 @@ pub fn make_struct(
10891084
values.insert(SmolStr::new(name), expr);
10901085
}
10911086

1092-
llr_Expression::Struct {
1093-
ty: Rc::new(Struct { fields, name: name.into(), rust_attributes: None }),
1094-
values,
1095-
}
1087+
llr_Expression::Struct { ty: Rc::new(Struct { fields, name: name.into() }), values }
10961088
}

internal/compiler/llr/lower_to_item_tree.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,10 +615,7 @@ fn lower_geometry(
615615
values
616616
.insert(f.into(), super::Expression::PropertyReference(ctx.map_property_reference(v)));
617617
}
618-
super::Expression::Struct {
619-
ty: Rc::new(Struct { fields, name: StructName::None, rust_attributes: None }),
620-
values,
621-
}
618+
super::Expression::Struct { ty: Rc::new(Struct { fields, name: StructName::None }), values }
622619
}
623620

624621
fn get_property_analysis(elem: &ElementRc, p: &str) -> crate::object_tree::PropertyAnalysis {

internal/compiler/object_tree.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,10 @@ impl Document {
9898
diag: &mut BuildDiagnostics,
9999
local_registry: &mut TypeRegister,
100100
inner_types: &mut Vec<Type>| {
101-
let rust_attributes = n.AtRustAttr().map(|child| vec![child.text().to_smolstr()]);
102101
let ty = type_struct_from_node(
103102
n.ObjectType(),
104103
diag,
105104
local_registry,
106-
rust_attributes,
107105
parser::identifier_text(&n.DeclaredIdentifier()),
108106
);
109107
assert!(matches!(ty, Type::Struct(_)));
@@ -2003,7 +2001,7 @@ pub fn type_from_node(
20032001
}
20042002
prop_type
20052003
} else if let Some(object_node) = node.ObjectType() {
2006-
type_struct_from_node(object_node, diag, tr, None, None)
2004+
type_struct_from_node(object_node, diag, tr, None)
20072005
} else if let Some(array_node) = node.ArrayType() {
20082006
Type::Array(Rc::new(type_from_node(array_node.Type(), diag, tr)))
20092007
} else {
@@ -2017,7 +2015,6 @@ pub fn type_struct_from_node(
20172015
object_node: syntax_nodes::ObjectType,
20182016
diag: &mut BuildDiagnostics,
20192017
tr: &TypeRegister,
2020-
rust_attributes: Option<Vec<SmolStr>>,
20212018
name: Option<SmolStr>,
20222019
) -> Type {
20232020
let fields = object_node
@@ -2032,7 +2029,6 @@ pub fn type_struct_from_node(
20322029
Type::Struct(Rc::new(Struct {
20332030
fields,
20342031
name: name.map_or(StructName::None, |name| StructName::User { name, node: object_node }),
2035-
rust_attributes,
20362032
}))
20372033
}
20382034

internal/compiler/passes/compile_paths.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ fn compile_path_from_string_literal(
164164
])
165165
.collect(),
166166
name: BuiltinPrivateStruct::Point.into(),
167-
rust_attributes: None,
168167
});
169168

170169
let mut points = Vec::new();

0 commit comments

Comments
 (0)