fix: import type inference result from other modules (#2168)
Some checks failed
tinymist::auto_tag / auto-tag (push) Has been cancelled
tinymist::ci / Duplicate Actions Detection (push) Has been cancelled
tinymist::ci / Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) (push) Has been cancelled
tinymist::ci / Check Minimum Rust version and Tests (Windows) (push) Has been cancelled
tinymist::ci / prepare-build (push) Has been cancelled
tinymist::gh_pages / build-gh-pages (push) Has been cancelled
tinymist::ci / announce (push) Has been cancelled
tinymist::ci / build (push) Has been cancelled

fix #2131
This commit is contained in:
Myriad-Dreamin 2025-10-15 11:22:39 +08:00 committed by GitHub
parent d80199d744
commit 29a10c144e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 215 additions and 39 deletions

View file

@ -512,8 +512,18 @@ impl Decl {
})
}
/// Creates a module declaration with a name and file ID.
pub fn module(name: Interned<str>, fid: TypstFileId) -> Self {
/// Creates a module declaration with a file ID.
pub fn module(fid: TypstFileId) -> Self {
let name = {
let stem = fid.vpath().as_rooted_path().file_stem();
stem.and_then(|s| Some(Interned::new_str(s.to_str()?)))
.unwrap_or_default()
};
Self::Module(ModuleDecl { name, fid })
}
/// Creates a module declaration with a name and a file ID.
pub fn module_with_name(name: Interned<str>, fid: TypstFileId) -> Self {
Self::Module(ModuleDecl { name, fid })
}

View file

@ -202,8 +202,7 @@ fn analyze_import_source(ctx: &LocalContext, types: &TypeInfo, s: ast::Expr) ->
return Some(types.simplify(res, false));
}
let m = ctx.module_by_syntax(s.to_untyped())?;
Some(Ty::Value(InsTy::new_at(m, s.span())))
ctx.module_term_by_syntax(s.to_untyped(), false)
}
pub(crate) enum ScopeCheckKind {

View file

@ -11,7 +11,7 @@ use rustc_hash::FxHashMap;
use tinymist_analysis::docs::DocString;
use tinymist_analysis::stats::AllocStats;
use tinymist_analysis::syntax::classify_def_loosely;
use tinymist_analysis::ty::term_value;
use tinymist_analysis::ty::{BuiltinTy, InsTy, term_value};
use tinymist_analysis::{analyze_expr_, analyze_import_};
use tinymist_lint::{KnownIssues, LintInfo};
use tinymist_project::{LspComputeGraph, LspWorld, TaskWhen};
@ -700,51 +700,68 @@ impl SharedContext {
})
}
/// Get a module by file id.
/// Gets a module by file id.
pub fn module_by_id(&self, fid: TypstFileId) -> SourceResult<Module> {
let source = self.source_by_id(fid).at(Span::detached())?;
self.module_by_src(source)
}
/// Get a module by string.
/// Gets a module by string.
pub fn module_by_str(&self, rr: String) -> Option<Module> {
let src = Source::new(*DETACHED_ENTRY, rr);
self.module_by_src(src).ok()
}
/// Get (Create) a module by source.
/// Gets (Creates) a module by source.
pub fn module_by_src(&self, source: Source) -> SourceResult<Module> {
eval_compat(&self.world, &source)
}
/// Try to load a module from the current source file.
pub fn module_by_syntax(&self, source: &SyntaxNode) -> Option<Value> {
/// Gets a module value from a given source file.
pub fn module_by_syntax(self: &Arc<Self>, source: &SyntaxNode) -> Option<Value> {
self.module_term_by_syntax(source, true)
.and_then(|ty| ty.value())
}
/// Gets a module term from a given source file. If `value` is true, it will
/// prefer to get a value instead of a term.
pub fn module_term_by_syntax(self: &Arc<Self>, source: &SyntaxNode, value: bool) -> Option<Ty> {
let (src, scope) = self.analyze_import(source);
if let Some(scope) = scope {
return Some(scope);
return Some(match scope {
Value::Module(m) if m.file_id().is_some() => {
Ty::Builtin(BuiltinTy::Module(Decl::module(m.file_id()?).into()))
}
scope => Ty::Value(InsTy::new(scope)),
});
}
match src {
Some(Value::Str(s)) => {
let id = resolve_id_by_path(&self.world, source.span().id()?, s.as_str())?;
self.module_by_id(id).ok().map(Value::Module)
Some(if value {
Ty::Value(InsTy::new(Value::Module(self.module_by_id(id).ok()?)))
} else {
Ty::Builtin(BuiltinTy::Module(Decl::module(id).into()))
})
}
_ => None,
}
}
/// Get the expression information of a source file.
/// Gets the expression information of a source file.
pub(crate) fn expr_stage_by_id(self: &Arc<Self>, fid: TypstFileId) -> Option<ExprInfo> {
Some(self.expr_stage(&self.source_by_id(fid).ok()?))
}
/// Get the expression information of a source file.
/// Gets the expression information of a source file.
pub(crate) fn expr_stage(self: &Arc<Self>, source: &Source) -> ExprInfo {
let mut route = ExprRoute::default();
self.expr_stage_(source, &mut route)
}
/// Get the expression information of a source file.
/// Gets the expression information of a source file.
pub(crate) fn expr_stage_(
self: &Arc<Self>,
source: &Source,
@ -769,13 +786,13 @@ impl SharedContext {
Some(self.expr_stage_(source, route).exports.clone())
}
/// Get the type check information of a source file.
/// Gets the type check information of a source file.
pub(crate) fn type_check(self: &Arc<Self>, source: &Source) -> Arc<TypeInfo> {
let mut route = TypeEnv::default();
self.type_check_(source, &mut route)
}
/// Get the type check information of a source file.
/// Gets the type check information of a source file.
pub(crate) fn type_check_(
self: &Arc<Self>,
source: &Source,
@ -796,7 +813,7 @@ impl SharedContext {
})
}
/// Get the lint result of a source file.
/// Gets the lint result of a source file.
#[typst_macros::time(span = source.root().span())]
pub(crate) fn lint(self: &Arc<Self>, source: &Source, issues: &KnownIssues) -> LintInfo {
let ei = self.expr_stage(source);

View file

@ -119,15 +119,11 @@ struct ScanDefCtx<'a> {
impl ScanDefCtx<'_> {
fn defs(&mut self, paths: EcoVec<&str>, ei: ExprInfo) -> DefInfo {
let name = {
let stem = ei.fid.vpath().as_rooted_path().file_stem();
stem.and_then(|s| Some(Interned::new_str(s.to_str()?)))
.unwrap_or_default()
};
let module_decl = Decl::module(name.clone(), ei.fid).into();
let module_decl = Decl::module(ei.fid);
let key = module_decl.name().clone();
let site = Some(self.root);
let paths = paths.clone();
self.def(&name, paths, site.as_ref(), &module_decl, None)
self.def(&key, paths, site.as_ref(), &module_decl.into(), None)
}
fn expr(

View file

@ -0,0 +1,9 @@
/// path: base.typ
/// - body (content): The body of the body
/// -> content
#let todo(body) = body; // redefine just for auto-completion
-----
/// contains: todo
#import "base.typ" as baz: *
#to(/* range -2..0 */ );

View file

@ -0,0 +1,9 @@
/// path: base.typ
/// - body (content): The body of the body
/// -> content
#let todo(body) = body; // redefine just for auto-completion
-----
/// contains: todo
#import "base.typ": todo
#to(/* range -2..0 */ );

View file

@ -12,7 +12,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ
"kind": 3,
"label": "aa",
"labelDetails": {
"description": "() => any"
"description": "() => 1"
},
"sortText": "000",
"textEdit": {
@ -33,7 +33,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ
"kind": 3,
"label": "aab",
"labelDetails": {
"description": "() => any"
"description": "() => 1"
},
"sortText": "001",
"textEdit": {
@ -54,7 +54,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ
"kind": 3,
"label": "aabc",
"labelDetails": {
"description": "() => any"
"description": "() => 1"
},
"sortText": "002",
"textEdit": {
@ -75,7 +75,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ
"kind": 3,
"label": "aac",
"labelDetails": {
"description": "() => any"
"description": "() => 1"
},
"sortText": "003",
"textEdit": {
@ -101,7 +101,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ
"kind": 3,
"label": "aabc",
"labelDetails": {
"description": "() => any"
"description": "() => 1"
},
"sortText": "002",
"textEdit": {
@ -122,7 +122,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/import_star.typ
"kind": 3,
"label": "aac",
"labelDetails": {
"description": "() => any"
"description": "() => 1"
},
"sortText": "003",
"textEdit": {

View file

@ -0,0 +1,68 @@
---
source: crates/tinymist-query/src/completion.rs
description: Completion on o( (50..52)
expression: "JsonRepr::new_pure(results)"
input_file: crates/tinymist-query/src/fixtures/completion/import_star_typing.typ
---
[
{
"isIncomplete": false,
"items": [
{
"command": {
"command": "tinymist.triggerSuggestAndParameterHints",
"title": ""
},
"kind": 3,
"label": "todo",
"labelDetails": {
"description": "(content) => content"
},
"sortText": "218",
"textEdit": {
"newText": "todo(${1:})",
"range": {
"end": {
"character": 3,
"line": 2
},
"start": {
"character": 1,
"line": 2
}
}
}
}
]
},
{
"isIncomplete": false,
"items": [
{
"command": {
"command": "tinymist.triggerSuggestAndParameterHints",
"title": ""
},
"kind": 3,
"label": "todo",
"labelDetails": {
"description": "(content) => content"
},
"sortText": "218",
"textEdit": {
"newText": "todo(${1:})",
"range": {
"end": {
"character": 3,
"line": 2
},
"start": {
"character": 1,
"line": 2
}
}
}
}
]
}
]

View file

@ -0,0 +1,68 @@
---
source: crates/tinymist-query/src/completion.rs
description: Completion on o( (46..48)
expression: "JsonRepr::new_pure(results)"
input_file: crates/tinymist-query/src/fixtures/completion/import_typing.typ
---
[
{
"isIncomplete": false,
"items": [
{
"command": {
"command": "tinymist.triggerSuggestAndParameterHints",
"title": ""
},
"kind": 3,
"label": "todo",
"labelDetails": {
"description": "(content) => content"
},
"sortText": "217",
"textEdit": {
"newText": "todo(${1:})",
"range": {
"end": {
"character": 3,
"line": 2
},
"start": {
"character": 1,
"line": 2
}
}
}
}
]
},
{
"isIncomplete": false,
"items": [
{
"command": {
"command": "tinymist.triggerSuggestAndParameterHints",
"title": ""
},
"kind": 3,
"label": "todo",
"labelDetails": {
"description": "(content) => content"
},
"sortText": "217",
"textEdit": {
"newText": "todo(${1:})",
"range": {
"end": {
"character": 3,
"line": 2
},
"start": {
"character": 1,
"line": 2
}
}
}
}
]
}
]

View file

@ -12,7 +12,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/item_shadow2.typ
"kind": 3,
"label": "base",
"labelDetails": {
"description": "() => any"
"description": "() => 1"
},
"sortText": "009",
"textEdit": {
@ -38,7 +38,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/item_shadow2.typ
"kind": 3,
"label": "base",
"labelDetails": {
"description": "() => any"
"description": "() => 1"
},
"sortText": "009",
"textEdit": {

View file

@ -12,7 +12,7 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-core-slides.typ
"kind": 3,
"label": "config-xxx",
"labelDetails": {
"description": "() => any"
"description": "() => none"
},
"sortText": "033",
"textEdit": {

View file

@ -43,7 +43,7 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-cover-with-rec
"labelDetails": {
"description": "type"
},
"sortText": "203",
"sortText": "204",
"textEdit": {
"newText": "stroke(${1:})",
"range": {

View file

@ -76,7 +76,7 @@ input_file: crates/tinymist-query/src/fixtures/pkgs/touying-utils-markup-text.ty
"labelDetails": {
"description": "type"
},
"sortText": "199",
"sortText": "200",
"textEdit": {
"newText": "str",
"range": {

View file

@ -716,7 +716,7 @@ impl ExprWorker<'_> {
// todo: dyn resolve src_expr
match m.file_id() {
Some(fid) => Some(Expr::Decl(
Decl::module(m.name().unwrap().into(), fid).into(),
Decl::module_with_name(m.name().unwrap().into(), fid).into(),
)),
None => Some(Expr::Type(Ty::Value(InsTy::new(Value::Module(m))))),
}
@ -751,7 +751,7 @@ impl ExprWorker<'_> {
) -> Option<Expr> {
let fid = resolve_id_by_path(&self.ctx.world, self.fid, src)?;
let name = Decl::calc_path_stem(src);
let module = Expr::Decl(Decl::module(name.clone(), fid).into());
let module = Expr::Decl(Decl::module_with_name(name.clone(), fid).into());
let import_path = if is_import {
Decl::import_path(source.span(), name)

View file

@ -33,7 +33,7 @@ fn test_lsp() {
});
let hash = replay_log(&root.join("vscode"));
insta::assert_snapshot!(hash, @"siphash128_13:5019cb39687d1a16853bc80320d00e26");
insta::assert_snapshot!(hash, @"siphash128_13:37838db38884e581e48751286df407d0");
}
}