diff options
Diffstat (limited to 'crates')
20 files changed, 136 insertions, 41 deletions
diff --git a/crates/typst-eval/src/call.rs b/crates/typst-eval/src/call.rs index 6f0ec1fc..c68bef96 100644 --- a/crates/typst-eval/src/call.rs +++ b/crates/typst-eval/src/call.rs @@ -315,13 +315,15 @@ fn eval_field_call( (target, args) }; + let field_span = field.span(); + let sink = (&mut vm.engine, field_span); if let Some(callee) = target.ty().scope().get(&field) { args.insert(0, target_expr.span(), target); - Ok(FieldCall::Normal(callee.read().clone(), args)) + Ok(FieldCall::Normal(callee.read_checked(sink).clone(), args)) } else if let Value::Content(content) = &target { if let Some(callee) = content.elem().scope().get(&field) { args.insert(0, target_expr.span(), target); - Ok(FieldCall::Normal(callee.read().clone(), args)) + Ok(FieldCall::Normal(callee.read_checked(sink).clone(), args)) } else { bail!(missing_field_call_error(target, field)) } @@ -331,7 +333,7 @@ fn eval_field_call( ) { // Certain value types may have their own ways to access method fields. // e.g. `$arrow.r(v)$`, `table.cell[..]` - let value = target.field(&field).at(field.span())?; + let value = target.field(&field, sink).at(field_span)?; Ok(FieldCall::Normal(value, args)) } else { // Otherwise we cannot call this field. @@ -364,7 +366,7 @@ fn missing_field_call_error(target: Value, field: Ident) -> SourceDiagnostic { field.as_str(), )); } - _ if target.field(&field).is_ok() => { + _ if target.field(&field, ()).is_ok() => { error.hint(eco_format!( "did you mean to access the field `{}`?", field.as_str(), diff --git a/crates/typst-eval/src/code.rs b/crates/typst-eval/src/code.rs index 4ac48186..a7b6b6f9 100644 --- a/crates/typst-eval/src/code.rs +++ b/crates/typst-eval/src/code.rs @@ -154,7 +154,13 @@ impl Eval for ast::Ident<'_> { type Output = Value; fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { - Ok(vm.scopes.get(&self).at(self.span())?.read().clone()) + let span = self.span(); + Ok(vm + .scopes + .get(&self) + .at(span)? + .read_checked((&mut vm.engine, span)) + .clone()) } } @@ -310,8 +316,9 @@ impl Eval for ast::FieldAccess<'_> { fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { let value = self.target().eval(vm)?; let field = self.field(); + let field_span = field.span(); - let err = match value.field(&field).at(field.span()) { + let err = match value.field(&field, (&mut vm.engine, field_span)).at(field_span) { Ok(value) => return Ok(value), Err(err) => err, }; diff --git a/crates/typst-eval/src/math.rs b/crates/typst-eval/src/math.rs index 23b293f2..0e271a08 100644 --- a/crates/typst-eval/src/math.rs +++ b/crates/typst-eval/src/math.rs @@ -35,7 +35,13 @@ impl Eval for ast::MathIdent<'_> { type Output = Value; fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { - Ok(vm.scopes.get_in_math(&self).at(self.span())?.read().clone()) + let span = self.span(); + Ok(vm + .scopes + .get_in_math(&self) + .at(span)? + .read_checked((&mut vm.engine, span)) + .clone()) } } diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs index f68c925d..c1f08cf0 100644 --- a/crates/typst-ide/src/complete.rs +++ b/crates/typst-ide/src/complete.rs @@ -414,7 +414,7 @@ fn field_access_completions( // with method syntax; // 2. We can unwrap the field's value since it's a field belonging to // this value's type, so accessing it should not fail. - ctx.value_completion(field, &value.field(field).unwrap()); + ctx.value_completion(field, &value.field(field, ()).unwrap()); } match value { diff --git a/crates/typst-library/src/diag.rs b/crates/typst-library/src/diag.rs index bd4c90a1..49cbd02c 100644 --- a/crates/typst-library/src/diag.rs +++ b/crates/typst-library/src/diag.rs @@ -11,6 +11,7 @@ use ecow::{eco_vec, EcoVec}; use typst_syntax::package::{PackageSpec, PackageVersion}; use typst_syntax::{Span, Spanned, SyntaxError}; +use crate::engine::Engine; use crate::{World, WorldExt}; /// Early-return with a [`StrResult`] or [`SourceResult`]. @@ -228,6 +229,23 @@ impl From<SyntaxError> for SourceDiagnostic { } } +/// Destination for a deprecation message when accessing a deprecated value. +pub trait DeprecationSink { + /// Emits the given deprecation message into this sink. + fn emit(self, message: &str); +} + +impl DeprecationSink for () { + fn emit(self, _: &str) {} +} + +impl DeprecationSink for (&mut Engine<'_>, Span) { + /// Emits the deprecation message as a warning. + fn emit(self, message: &str) { + self.0.sink.warn(SourceDiagnostic::warning(self.1, message)); + } +} + /// A part of a diagnostic's [trace](SourceDiagnostic::trace). #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Tracepoint { diff --git a/crates/typst-library/src/foundations/func.rs b/crates/typst-library/src/foundations/func.rs index 741b6633..3ed1562f 100644 --- a/crates/typst-library/src/foundations/func.rs +++ b/crates/typst-library/src/foundations/func.rs @@ -9,7 +9,7 @@ use ecow::{eco_format, EcoString}; use typst_syntax::{ast, Span, SyntaxNode}; use typst_utils::{singleton, LazyHash, Static}; -use crate::diag::{bail, At, SourceResult, StrResult}; +use crate::diag::{bail, At, DeprecationSink, SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ cast, repr, scope, ty, Args, Bytes, CastInfo, Content, Context, Element, IntoArgs, @@ -255,11 +255,15 @@ impl Func { } /// Get a field from this function's scope, if possible. - pub fn field(&self, field: &str) -> StrResult<&'static Value> { + pub fn field( + &self, + field: &str, + sink: impl DeprecationSink, + ) -> StrResult<&'static Value> { let scope = self.scope().ok_or("cannot access fields on user-defined functions")?; match scope.get(field) { - Some(binding) => Ok(binding.read()), + Some(binding) => Ok(binding.read_checked(sink)), None => match self.name() { Some(name) => bail!("function `{name}` does not contain field `{field}`"), None => bail!("function does not contain field `{field}`"), diff --git a/crates/typst-library/src/foundations/module.rs b/crates/typst-library/src/foundations/module.rs index 3259c17e..8d9626a1 100644 --- a/crates/typst-library/src/foundations/module.rs +++ b/crates/typst-library/src/foundations/module.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use ecow::{eco_format, EcoString}; use typst_syntax::FileId; -use crate::diag::{bail, StrResult}; +use crate::diag::{bail, DeprecationSink, StrResult}; use crate::foundations::{repr, ty, Content, Scope, Value}; /// An module of definitions. @@ -118,9 +118,9 @@ impl Module { } /// Try to access a definition in the module. - pub fn field(&self, field: &str) -> StrResult<&Value> { + pub fn field(&self, field: &str, sink: impl DeprecationSink) -> StrResult<&Value> { match self.scope().get(field) { - Some(binding) => Ok(binding.read()), + Some(binding) => Ok(binding.read_checked(sink)), None => match &self.name { Some(name) => bail!("module `{name}` does not contain `{field}`"), None => bail!("module does not contain `{field}`"), diff --git a/crates/typst-library/src/foundations/scope.rs b/crates/typst-library/src/foundations/scope.rs index e73afeac..d6c5a8d0 100644 --- a/crates/typst-library/src/foundations/scope.rs +++ b/crates/typst-library/src/foundations/scope.rs @@ -10,7 +10,7 @@ use indexmap::IndexMap; use typst_syntax::Span; use typst_utils::Static; -use crate::diag::{bail, HintedStrResult, HintedString, StrResult}; +use crate::diag::{bail, DeprecationSink, HintedStrResult, HintedString, StrResult}; use crate::foundations::{ Element, Func, IntoValue, NativeElement, NativeFunc, NativeFuncData, NativeType, Type, Value, @@ -258,6 +258,8 @@ pub struct Binding { span: Span, /// The category of the binding. category: Option<Category>, + /// A deprecation message for the definition. + deprecation: Option<&'static str>, } /// The different kinds of slots. @@ -277,6 +279,7 @@ impl Binding { span, kind: BindingKind::Normal, category: None, + deprecation: None, } } @@ -285,11 +288,29 @@ impl Binding { Self::new(value, Span::detached()) } + /// Marks this binding as deprecated, with the given `message`. + pub fn deprecated(&mut self, message: &'static str) -> &mut Self { + self.deprecation = Some(message); + self + } + /// Read the value. pub fn read(&self) -> &Value { &self.value } + /// Read the value, checking for deprecation. + /// + /// As the `sink` + /// - pass `()` to ignore the message. + /// - pass `(&mut engine, span)` to emit a warning into the engine. + pub fn read_checked(&self, sink: impl DeprecationSink) -> &Value { + if let Some(message) = self.deprecation { + sink.emit(message); + } + &self.value + } + /// Try to write to the value. /// /// This fails if the value is a read-only closure capture. @@ -320,6 +341,11 @@ impl Binding { self.span } + /// A deprecation message for the value, if any. + pub fn deprecation(&self) -> Option<&'static str> { + self.deprecation + } + /// The category of the value, if any. pub fn category(&self) -> Option<Category> { self.category diff --git a/crates/typst-library/src/foundations/ty.rs b/crates/typst-library/src/foundations/ty.rs index 09f5efa1..40f7003c 100644 --- a/crates/typst-library/src/foundations/ty.rs +++ b/crates/typst-library/src/foundations/ty.rs @@ -8,7 +8,7 @@ use std::sync::LazyLock; use ecow::{eco_format, EcoString}; use typst_utils::Static; -use crate::diag::{bail, StrResult}; +use crate::diag::{bail, DeprecationSink, StrResult}; use crate::foundations::{ cast, func, AutoValue, Func, NativeFuncData, NoneValue, Repr, Scope, Value, }; @@ -94,9 +94,13 @@ impl Type { } /// Get a field from this type's scope, if possible. - pub fn field(&self, field: &str) -> StrResult<&'static Value> { + pub fn field( + &self, + field: &str, + sink: impl DeprecationSink, + ) -> StrResult<&'static Value> { match self.scope().get(field) { - Some(binding) => Ok(binding.read()), + Some(binding) => Ok(binding.read_checked(sink)), None => bail!("type {self} does not contain field `{field}`"), } } diff --git a/crates/typst-library/src/foundations/value.rs b/crates/typst-library/src/foundations/value.rs index 4fa380b4..854c2486 100644 --- a/crates/typst-library/src/foundations/value.rs +++ b/crates/typst-library/src/foundations/value.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use typst_syntax::{ast, Span}; use typst_utils::ArcExt; -use crate::diag::{HintedStrResult, HintedString, StrResult}; +use crate::diag::{DeprecationSink, HintedStrResult, HintedString, StrResult}; use crate::foundations::{ fields, ops, repr, Args, Array, AutoValue, Bytes, CastInfo, Content, Datetime, Decimal, Dict, Duration, Fold, FromValue, Func, IntoValue, Label, Module, @@ -155,15 +155,15 @@ impl Value { } /// Try to access a field on the value. - pub fn field(&self, field: &str) -> StrResult<Value> { + pub fn field(&self, field: &str, sink: impl DeprecationSink) -> StrResult<Value> { match self { Self::Symbol(symbol) => symbol.clone().modified(field).map(Self::Symbol), Self::Version(version) => version.component(field).map(Self::Int), Self::Dict(dict) => dict.get(field).cloned(), Self::Content(content) => content.field_by_name(field), - Self::Type(ty) => ty.field(field).cloned(), - Self::Func(func) => func.field(field).cloned(), - Self::Module(module) => module.field(field).cloned(), + Self::Type(ty) => ty.field(field, sink).cloned(), + Self::Func(func) => func.field(field, sink).cloned(), + Self::Module(module) => module.field(field, sink).cloned(), _ => fields::field(self, field), } } diff --git a/crates/typst-library/src/loading/cbor.rs b/crates/typst-library/src/loading/cbor.rs index 2bdeb80e..bd65e844 100644 --- a/crates/typst-library/src/loading/cbor.rs +++ b/crates/typst-library/src/loading/cbor.rs @@ -38,6 +38,7 @@ impl cbor { /// This function is deprecated. The [`cbor`] function now accepts bytes /// directly. #[func(title = "Decode CBOR")] + #[deprecated = "`cbor.decode` is deprecated, directly pass bytes to `cbor` instead"] pub fn decode( engine: &mut Engine, /// CBOR data. diff --git a/crates/typst-library/src/loading/csv.rs b/crates/typst-library/src/loading/csv.rs index 1cf656ae..d01d687b 100644 --- a/crates/typst-library/src/loading/csv.rs +++ b/crates/typst-library/src/loading/csv.rs @@ -100,6 +100,7 @@ impl csv { /// This function is deprecated. The [`csv`] function now accepts bytes /// directly. #[func(title = "Decode CSV")] + #[deprecated = "`csv.decode` is deprecated, directly pass bytes to `csv` instead"] pub fn decode( engine: &mut Engine, /// CSV data. diff --git a/crates/typst-library/src/loading/json.rs b/crates/typst-library/src/loading/json.rs index 035c5e4a..52c87371 100644 --- a/crates/typst-library/src/loading/json.rs +++ b/crates/typst-library/src/loading/json.rs @@ -69,6 +69,7 @@ impl json { /// This function is deprecated. The [`json`] function now accepts bytes /// directly. #[func(title = "Decode JSON")] + #[deprecated = "`json.decode` is deprecated, directly pass bytes to `json` instead"] pub fn decode( engine: &mut Engine, /// JSON data. diff --git a/crates/typst-library/src/loading/toml.rs b/crates/typst-library/src/loading/toml.rs index 402207b0..45611246 100644 --- a/crates/typst-library/src/loading/toml.rs +++ b/crates/typst-library/src/loading/toml.rs @@ -48,6 +48,7 @@ impl toml { /// This function is deprecated. The [`toml`] function now accepts bytes /// directly. #[func(title = "Decode TOML")] + #[deprecated = "`toml.decode` is deprecated, directly pass bytes to `toml` instead"] pub fn decode( engine: &mut Engine, /// TOML data. diff --git a/crates/typst-library/src/loading/xml.rs b/crates/typst-library/src/loading/xml.rs index ca467c23..0172071b 100644 --- a/crates/typst-library/src/loading/xml.rs +++ b/crates/typst-library/src/loading/xml.rs @@ -81,6 +81,7 @@ impl xml { /// This function is deprecated. The [`xml`] function now accepts bytes /// directly. #[func(title = "Decode XML")] + #[deprecated = "`xml.decode` is deprecated, directly pass bytes to `xml` instead"] pub fn decode( engine: &mut Engine, /// XML data. diff --git a/crates/typst-library/src/loading/yaml.rs b/crates/typst-library/src/loading/yaml.rs index 5767cb64..511c676c 100644 --- a/crates/typst-library/src/loading/yaml.rs +++ b/crates/typst-library/src/loading/yaml.rs @@ -59,6 +59,7 @@ impl yaml { /// This function is deprecated. The [`yaml`] function now accepts bytes /// directly. #[func(title = "Decode YAML")] + #[deprecated = "`yaml.decode` is deprecated, directly pass bytes to `yaml` instead"] pub fn decode( engine: &mut Engine, /// YAML data. diff --git a/crates/typst-library/src/visualize/image/mod.rs b/crates/typst-library/src/visualize/image/mod.rs index 07ebdabe..9306eb6f 100644 --- a/crates/typst-library/src/visualize/image/mod.rs +++ b/crates/typst-library/src/visualize/image/mod.rs @@ -171,6 +171,7 @@ impl ImageElem { /// #image.decode(changed) /// ``` #[func(title = "Decode Image")] + #[deprecated = "`image.decode` is deprecated, directly pass bytes to `image` instead"] pub fn decode( span: Span, /// The data to decode as an image. Can be a string for SVGs. diff --git a/crates/typst-library/src/visualize/mod.rs b/crates/typst-library/src/visualize/mod.rs index b0e627af..76849ac8 100644 --- a/crates/typst-library/src/visualize/mod.rs +++ b/crates/typst-library/src/visualize/mod.rs @@ -24,7 +24,7 @@ pub use self::shape::*; pub use self::stroke::*; pub use self::tiling::*; -use crate::foundations::{category, Category, Scope, Type}; +use crate::foundations::{category, Category, Element, Scope, Type}; /// Drawing and data visualization. /// @@ -49,8 +49,10 @@ pub(super) fn define(global: &mut Scope) { global.define_elem::<CircleElem>(); global.define_elem::<PolygonElem>(); global.define_elem::<CurveElem>(); - global.define_elem::<PathElem>(); - - // Compatibility. - global.define("pattern", Type::of::<Tiling>()); + global + .define("path", Element::of::<PathElem>()) + .deprecated("the `path` function is deprecated, use `curve` instead"); + global + .define("pattern", Type::of::<Tiling>()) + .deprecated("the name `pattern` is deprecated, use `tiling` instead"); } diff --git a/crates/typst-library/src/visualize/path.rs b/crates/typst-library/src/visualize/path.rs index 6aacb319..5d3439c0 100644 --- a/crates/typst-library/src/visualize/path.rs +++ b/crates/typst-library/src/visualize/path.rs @@ -23,7 +23,7 @@ use crate::visualize::{FillRule, Paint, Stroke}; /// ``` /// /// # Deprecation -/// This element is deprecated. The [`curve`] element should be used instead. +/// This function is deprecated. The [`curve`] function should be used instead. #[elem(Show)] pub struct PathElem { /// How to fill the path. diff --git a/crates/typst-macros/src/scope.rs b/crates/typst-macros/src/scope.rs index 8a2f1ce6..392ab1a5 100644 --- a/crates/typst-macros/src/scope.rs +++ b/crates/typst-macros/src/scope.rs @@ -31,18 +31,37 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> { let mut definitions = vec![]; let mut constructor = quote! { None }; for child in &mut item.items { - let def = match child { - syn::ImplItem::Const(item) => handle_const(&self_ty_expr, item)?, - syn::ImplItem::Fn(item) => match handle_fn(self_ty, item)? { - FnKind::Member(tokens) => tokens, - FnKind::Constructor(tokens) => { - constructor = tokens; - continue; - } - }, - syn::ImplItem::Verbatim(item) => handle_type_or_elem(item)?, + let bare: BareType; + let (mut def, attrs) = match child { + syn::ImplItem::Const(item) => { + (handle_const(&self_ty_expr, item)?, &item.attrs) + } + syn::ImplItem::Fn(item) => ( + match handle_fn(self_ty, item)? { + FnKind::Member(tokens) => tokens, + FnKind::Constructor(tokens) => { + constructor = tokens; + continue; + } + }, + &item.attrs, + ), + syn::ImplItem::Verbatim(item) => { + bare = syn::parse2(item.clone())?; + (handle_type_or_elem(&bare)?, &bare.attrs) + } _ => bail!(child, "unexpected item in scope"), }; + + if let Some(message) = attrs.iter().find_map(|attr| match &attr.meta { + syn::Meta::NameValue(pair) if pair.path.is_ident("deprecated") => { + Some(&pair.value) + } + _ => None, + }) { + def = quote! { #def.deprecated(#message) } + } + definitions.push(def); } @@ -61,6 +80,7 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> { #constructor } + #[allow(deprecated)] fn scope() -> #foundations::Scope { let mut scope = #foundations::Scope::deduplicating(); #(#definitions;)* @@ -78,8 +98,7 @@ fn handle_const(self_ty: &TokenStream, item: &syn::ImplItemConst) -> Result<Toke } /// Process a type item. -fn handle_type_or_elem(item: &TokenStream) -> Result<TokenStream> { - let item: BareType = syn::parse2(item.clone())?; +fn handle_type_or_elem(item: &BareType) -> Result<TokenStream> { let ident = &item.ident; let define = if item.attrs.iter().any(|attr| attr.path().is_ident("elem")) { quote! { define_elem } |
