summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2025-02-04 10:38:31 +0100
committerGitHub <noreply@github.com>2025-02-04 09:38:31 +0000
commit50ccd7d60f078f3617bfed5c4e8e1fd7d45ec340 (patch)
tree22c12abf76d2b2c20b49b569167ddf60fbe5b348 /crates
parent5b3593e571826ae44a3aeb0e0f6f09face7291ac (diff)
Scope deprecations (#5798)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-eval/src/call.rs10
-rw-r--r--crates/typst-eval/src/code.rs11
-rw-r--r--crates/typst-eval/src/math.rs8
-rw-r--r--crates/typst-ide/src/complete.rs2
-rw-r--r--crates/typst-library/src/diag.rs18
-rw-r--r--crates/typst-library/src/foundations/func.rs10
-rw-r--r--crates/typst-library/src/foundations/module.rs6
-rw-r--r--crates/typst-library/src/foundations/scope.rs28
-rw-r--r--crates/typst-library/src/foundations/ty.rs10
-rw-r--r--crates/typst-library/src/foundations/value.rs10
-rw-r--r--crates/typst-library/src/loading/cbor.rs1
-rw-r--r--crates/typst-library/src/loading/csv.rs1
-rw-r--r--crates/typst-library/src/loading/json.rs1
-rw-r--r--crates/typst-library/src/loading/toml.rs1
-rw-r--r--crates/typst-library/src/loading/xml.rs1
-rw-r--r--crates/typst-library/src/loading/yaml.rs1
-rw-r--r--crates/typst-library/src/visualize/image/mod.rs1
-rw-r--r--crates/typst-library/src/visualize/mod.rs12
-rw-r--r--crates/typst-library/src/visualize/path.rs2
-rw-r--r--crates/typst-macros/src/scope.rs43
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 }