mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 14:21:16 +00:00
Don't load document twice if they are imported twice
Also protect against cyclic imports
This commit is contained in:
parent
a4b476bdf3
commit
2d55b2a51a
5 changed files with 123 additions and 38 deletions
|
@ -95,7 +95,7 @@ pub fn compile_syntax_node(
|
||||||
Cow::from("ugly")
|
Cow::from("ugly")
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut all_docs = vec![];
|
let mut all_docs = typeloader::LoadedDocuments::default();
|
||||||
if doc_node.source_file.is_some() {
|
if doc_node.source_file.is_some() {
|
||||||
typeloader::load_dependencies_recursively(
|
typeloader::load_dependencies_recursively(
|
||||||
&doc_node,
|
&doc_node,
|
||||||
|
|
17
sixtyfps_compiler/tests/syntax/imports/cyclic_import.60
Normal file
17
sixtyfps_compiler/tests/syntax/imports/cyclic_import.60
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
/* LICENSE BEGIN
|
||||||
|
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
||||||
|
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
||||||
|
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
This file is also available under commercial licensing terms.
|
||||||
|
Please contact info@sixtyfps.io for more information.
|
||||||
|
LICENSE END */
|
||||||
|
|
||||||
|
import { Rec12 } from "../../typeloader/recursive_import1.60";
|
||||||
|
// ^error{No exported type called Rec12 found in.*recursive_import1.60}
|
||||||
|
Blah := Rec12 {
|
||||||
|
// ^error{Unknown type Rec12}
|
||||||
|
width: 100px;
|
||||||
|
}
|
18
sixtyfps_compiler/tests/typeloader/recursive_import1.60
Normal file
18
sixtyfps_compiler/tests/typeloader/recursive_import1.60
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/* LICENSE BEGIN
|
||||||
|
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
||||||
|
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
||||||
|
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
This file is also available under commercial licensing terms.
|
||||||
|
Please contact info@sixtyfps.io for more information.
|
||||||
|
LICENSE END */
|
||||||
|
import { Rec2 } from "./recursive_import2.60";
|
||||||
|
|
||||||
|
export Rec1 := Rectangle {
|
||||||
|
property <int> Hello: 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
export Rect12 := Rec2 {
|
||||||
|
property <int> World: 43;
|
||||||
|
}
|
20
sixtyfps_compiler/tests/typeloader/recursive_import2.60
Normal file
20
sixtyfps_compiler/tests/typeloader/recursive_import2.60
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/* LICENSE BEGIN
|
||||||
|
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
||||||
|
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
||||||
|
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
This file is also available under commercial licensing terms.
|
||||||
|
Please contact info@sixtyfps.io for more information.
|
||||||
|
LICENSE END */
|
||||||
|
import { Rec1 } from "./recursive_import1.60";
|
||||||
|
// ^error{Recursive import of .*recursive_import1.60}
|
||||||
|
|
||||||
|
export Rec2 := Rectangle {
|
||||||
|
property <int> Foo: 44;
|
||||||
|
}
|
||||||
|
|
||||||
|
export Rect21 := Rec1 {
|
||||||
|
// ^error{Unknown type Rec1}
|
||||||
|
property <int> Bar: 45;
|
||||||
|
}
|
|
@ -7,10 +7,11 @@
|
||||||
This file is also available under commercial licensing terms.
|
This file is also available under commercial licensing terms.
|
||||||
Please contact info@sixtyfps.io for more information.
|
Please contact info@sixtyfps.io for more information.
|
||||||
LICENSE END */
|
LICENSE END */
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::{cell::RefCell, collections::BTreeMap};
|
|
||||||
|
|
||||||
use crate::diagnostics::{BuildDiagnostics, FileDiagnostics, SourceFile};
|
use crate::diagnostics::{BuildDiagnostics, FileDiagnostics, SourceFile};
|
||||||
use crate::object_tree::Document;
|
use crate::object_tree::Document;
|
||||||
|
@ -18,19 +19,26 @@ use crate::parser::{syntax_nodes, SyntaxKind, SyntaxTokenWithSourceFile};
|
||||||
use crate::typeregister::TypeRegister;
|
use crate::typeregister::TypeRegister;
|
||||||
use crate::CompilerConfiguration;
|
use crate::CompilerConfiguration;
|
||||||
|
|
||||||
pub struct OpenFile<'a> {
|
/// Storage for a cache of all loaded documents
|
||||||
pub path: PathBuf,
|
#[derive(Default)]
|
||||||
pub file: Box<dyn Read + 'a>,
|
pub struct LoadedDocuments {
|
||||||
|
/// maps from the canonical file name to the object_tree::Document
|
||||||
|
docs: HashMap<PathBuf, Document>,
|
||||||
|
currently_loading: HashSet<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DirectoryAccess<'a> {
|
struct OpenFile<'a> {
|
||||||
|
path: PathBuf,
|
||||||
|
file: Box<dyn Read + 'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DirectoryAccess<'a> {
|
||||||
fn try_open(&self, file_path: String) -> Option<OpenFile<'a>>;
|
fn try_open(&self, file_path: String) -> Option<OpenFile<'a>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DirectoryAccess<'a> for PathBuf {
|
impl<'a> DirectoryAccess<'a> for PathBuf {
|
||||||
fn try_open(&self, file_path: String) -> Option<OpenFile<'a>> {
|
fn try_open(&self, file_path: String) -> Option<OpenFile<'a>> {
|
||||||
let mut candidate = (*self).clone();
|
let candidate = self.join(file_path);
|
||||||
candidate.push(file_path);
|
|
||||||
|
|
||||||
std::fs::File::open(&candidate)
|
std::fs::File::open(&candidate)
|
||||||
.ok()
|
.ok()
|
||||||
|
@ -66,7 +74,7 @@ pub fn load_dependencies_recursively<'a>(
|
||||||
global_type_registry: &Rc<RefCell<TypeRegister>>,
|
global_type_registry: &Rc<RefCell<TypeRegister>>,
|
||||||
compiler_config: &CompilerConfiguration,
|
compiler_config: &CompilerConfiguration,
|
||||||
builtin_library: Option<&'a VirtualDirectory<'a>>,
|
builtin_library: Option<&'a VirtualDirectory<'a>>,
|
||||||
all_documents: &mut Vec<Document>,
|
all_documents: &mut LoadedDocuments,
|
||||||
build_diagnostics: &mut BuildDiagnostics,
|
build_diagnostics: &mut BuildDiagnostics,
|
||||||
) {
|
) {
|
||||||
let dependencies =
|
let dependencies =
|
||||||
|
@ -94,13 +102,26 @@ fn load_dependency<'a>(
|
||||||
importer_diagnostics: &mut FileDiagnostics,
|
importer_diagnostics: &mut FileDiagnostics,
|
||||||
compiler_config: &CompilerConfiguration,
|
compiler_config: &CompilerConfiguration,
|
||||||
builtin_library: Option<&'a VirtualDirectory<'a>>,
|
builtin_library: Option<&'a VirtualDirectory<'a>>,
|
||||||
all_documents: &mut Vec<Document>,
|
all_documents: &mut LoadedDocuments,
|
||||||
build_diagnostics: &mut BuildDiagnostics,
|
build_diagnostics: &mut BuildDiagnostics,
|
||||||
) {
|
) {
|
||||||
|
let path_canon = path.canonicalize().unwrap_or(path.clone());
|
||||||
|
|
||||||
|
let doc = if let Some(doc) = all_documents.docs.get(path_canon.as_path()) {
|
||||||
|
doc
|
||||||
|
} else {
|
||||||
|
if !all_documents.currently_loading.insert(path_canon.clone()) {
|
||||||
|
importer_diagnostics.push_error(
|
||||||
|
format!("Recursive import of {}", path.display()),
|
||||||
|
&imported_types.import_token,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let (dependency_doc, mut dependency_diagnostics) =
|
let (dependency_doc, mut dependency_diagnostics) =
|
||||||
crate::parser::parse(imported_types.source_code, Some(&path));
|
crate::parser::parse(imported_types.source_code, Some(&path));
|
||||||
|
|
||||||
dependency_diagnostics.current_path = SourceFile::new(path);
|
dependency_diagnostics.current_path = SourceFile::new(path.clone());
|
||||||
|
|
||||||
let dependency_doc: syntax_nodes::Document = dependency_doc.into();
|
let dependency_doc: syntax_nodes::Document = dependency_doc.into();
|
||||||
|
|
||||||
|
@ -122,6 +143,20 @@ fn load_dependency<'a>(
|
||||||
&dependency_registry,
|
&dependency_registry,
|
||||||
);
|
);
|
||||||
crate::passes::resolving::resolve_expressions(&doc, build_diagnostics);
|
crate::passes::resolving::resolve_expressions(&doc, build_diagnostics);
|
||||||
|
|
||||||
|
// Add diagnostics regardless whether they're empty or not. This is used by the syntax_tests to
|
||||||
|
// also verify that imported files have no errors.
|
||||||
|
build_diagnostics.add(dependency_diagnostics);
|
||||||
|
|
||||||
|
let _ok = all_documents.currently_loading.remove(path_canon.as_path());
|
||||||
|
assert!(_ok);
|
||||||
|
|
||||||
|
match all_documents.docs.entry(path_canon) {
|
||||||
|
std::collections::hash_map::Entry::Occupied(_) => unreachable!(),
|
||||||
|
std::collections::hash_map::Entry::Vacant(e) => e.insert(doc),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let exports = doc.exports();
|
let exports = doc.exports();
|
||||||
|
|
||||||
for import_name in imported_types.type_names {
|
for import_name in imported_types.type_names {
|
||||||
|
@ -140,7 +175,7 @@ fn load_dependency<'a>(
|
||||||
format!(
|
format!(
|
||||||
"No exported type called {} found in {}",
|
"No exported type called {} found in {}",
|
||||||
import_name.external_name,
|
import_name.external_name,
|
||||||
dependency_diagnostics.current_path.to_string_lossy()
|
path.display()
|
||||||
),
|
),
|
||||||
&imported_types.import_token,
|
&imported_types.import_token,
|
||||||
);
|
);
|
||||||
|
@ -150,11 +185,6 @@ fn load_dependency<'a>(
|
||||||
|
|
||||||
registry_to_populate.borrow_mut().add_with_name(import_name.internal_name, imported_type);
|
registry_to_populate.borrow_mut().add_with_name(import_name.internal_name, imported_type);
|
||||||
}
|
}
|
||||||
all_documents.push(doc);
|
|
||||||
|
|
||||||
// Add diagnostics regardless whether they're empty or not. This is used by the syntax_tests to
|
|
||||||
// also verify that imported files have no errors.
|
|
||||||
build_diagnostics.add(dependency_diagnostics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ImportedName {
|
pub struct ImportedName {
|
||||||
|
@ -292,7 +322,7 @@ fn test_dependency_loading() {
|
||||||
let registry = Rc::new(RefCell::new(TypeRegister::new(&global_registry)));
|
let registry = Rc::new(RefCell::new(TypeRegister::new(&global_registry)));
|
||||||
|
|
||||||
let mut build_diagnostics = BuildDiagnostics::default();
|
let mut build_diagnostics = BuildDiagnostics::default();
|
||||||
let mut docs = vec![];
|
let mut docs = Default::default();
|
||||||
|
|
||||||
load_dependencies_recursively(
|
load_dependencies_recursively(
|
||||||
&doc_node,
|
&doc_node,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue