mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 13:13:43 +00:00
parent
ed79045588
commit
692e53880b
12 changed files with 381 additions and 43 deletions
|
@ -31,7 +31,7 @@ pub fn bind_ty_ctx(input: TokenStream) -> TokenStream {
|
|||
|
||||
quote! {
|
||||
impl #impl_generics TyCtx for #name #ty_generics #where_clause {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<DynTypeBounds> {
|
||||
self.#bind_name.global_bounds(var, pol)
|
||||
}
|
||||
fn local_bind_of(&self, var: &Interned<TypeVar>) -> Option<Ty> {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use hashbrown::HashSet;
|
||||
use tinymist_derive::BindTyCtx;
|
||||
|
||||
use super::{prelude::*, ParamAttrs, ParamTy, SharedContext};
|
||||
use super::{prelude::*, DynTypeBounds, ParamAttrs, ParamTy, SharedContext};
|
||||
use super::{
|
||||
ArgsTy, Sig, SigChecker, SigShape, SigSurfaceKind, SigTy, Ty, TyCtx, TyCtxMut, TypeBounds,
|
||||
TypeScheme, TypeVar,
|
||||
|
@ -106,7 +106,7 @@ pub(crate) struct PostTypeChecker<'a> {
|
|||
}
|
||||
|
||||
impl TyCtx for PostTypeChecker<'_> {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<DynTypeBounds> {
|
||||
self.info.global_bounds(var, pol)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ use super::{
|
|||
use crate::analysis::PostTypeChecker;
|
||||
use crate::docs::{UntypedDefDocs, UntypedSignatureDocs, UntypedVarDocs};
|
||||
use crate::syntax::get_non_strict_def_target;
|
||||
use crate::ty::{DynTypeBounds, ParamAttrs};
|
||||
use crate::ty::{InsTy, TyCtx};
|
||||
use crate::ty::{ParamAttrs, TypeBounds};
|
||||
use crate::upstream::truncated_repr;
|
||||
|
||||
/// Describes a function signature.
|
||||
|
|
|
@ -6,8 +6,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
|||
use tinymist_derive::BindTyCtx;
|
||||
|
||||
use super::{
|
||||
prelude::*, BuiltinTy, FlowVarKind, SharedContext, TyCtxMut, TypeBounds, TypeScheme, TypeVar,
|
||||
TypeVarBounds,
|
||||
prelude::*, BuiltinTy, DynTypeBounds, FlowVarKind, SharedContext, TyCtxMut, TypeScheme,
|
||||
TypeVar, TypeVarBounds,
|
||||
};
|
||||
use crate::{
|
||||
syntax::{Decl, DeclExpr, Expr, ExprInfo, UnaryOp},
|
||||
|
@ -95,7 +95,7 @@ pub(crate) struct TypeChecker<'a> {
|
|||
}
|
||||
|
||||
impl TyCtx for TypeChecker<'_> {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<TypeBounds> {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, pol: bool) -> Option<DynTypeBounds> {
|
||||
self.info.global_bounds(var, pol)
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ impl TypeChecker<'_> {
|
|||
match &w.bounds {
|
||||
FlowVarKind::Strong(w) | FlowVarKind::Weak(w) => {
|
||||
let mut w = w.write();
|
||||
w.ubs.push(bound);
|
||||
w.ubs.insert_mut(bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ impl TypeChecker<'_> {
|
|||
match &w.bounds {
|
||||
FlowVarKind::Strong(v) | FlowVarKind::Weak(v) => {
|
||||
let mut v = v.write();
|
||||
v.lbs.push(bound);
|
||||
v.lbs.insert_mut(bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -385,8 +385,8 @@ impl TypeChecker<'_> {
|
|||
let res_ty = if let Some(annotated) = &docstring.res_ty {
|
||||
self.constrain(&body, annotated);
|
||||
Ty::Let(Interned::new(TypeBounds {
|
||||
lbs: eco_vec![body],
|
||||
ubs: eco_vec![annotated.clone()],
|
||||
lbs: vec![body],
|
||||
ubs: vec![annotated.clone()],
|
||||
}))
|
||||
} else {
|
||||
body
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
// NOTE: we avoid a possible syntax error in the future when custom elements are added and self may become a keyword by appending an underscore
|
||||
#import "@preview/t4t:0.3.2"
|
||||
|
||||
#let _resolve(elem, it, field) = {
|
||||
if it.has(field) {
|
||||
it.at(field)
|
||||
} else {
|
||||
// we can't func.at(field) to resolve the field
|
||||
// eval(repr(elem) + "." + field)
|
||||
elem.at(field)
|
||||
}
|
||||
}
|
||||
|
||||
/// The default figure show rule. The active set rules will be used.
|
||||
///
|
||||
/// This function is contextual.
|
||||
///
|
||||
/// - self_ (content): The figure to show using the defualt show rule.
|
||||
/// -> content
|
||||
#let show-figure(self_) = {
|
||||
// NOTE: this is written to be close to the rust impl to make changes easier to compare
|
||||
|
||||
let realized = self_.body
|
||||
|
||||
let caption = _resolve(figure, self_, "caption")
|
||||
if caption != none {
|
||||
let v = v(self_.gap, weak: true)
|
||||
let position = _resolve(figure.caption, caption, "position")
|
||||
realized = if position == top {
|
||||
caption + v + realized
|
||||
} else {
|
||||
realized + v + caption
|
||||
}
|
||||
}
|
||||
|
||||
realized = {
|
||||
set align(center)
|
||||
block(realized)
|
||||
}
|
||||
|
||||
let placement = _resolve(figure, self_, "placement")
|
||||
if placement != none {
|
||||
realized = place(placement, float: true)
|
||||
}
|
||||
|
||||
realized
|
||||
}
|
||||
|
||||
#let _numbering = numbering
|
||||
|
||||
#let apply-for-all(
|
||||
values,
|
||||
rule,
|
||||
) = (
|
||||
outer => {
|
||||
show: inner => {
|
||||
values.map(rule).fold(inner, (acc, f) => f(acc))
|
||||
}
|
||||
|
||||
outer
|
||||
}
|
||||
)
|
||||
|
||||
#let gather-kinds(body) = {
|
||||
if t4t.is.elem(figure, body) {
|
||||
if body.at("kind", default: auto) != auto {
|
||||
return (figure.kind,)
|
||||
}
|
||||
} else if body.has("children") {
|
||||
return body.children.map(gather-kinds).flatten().dedup()
|
||||
}
|
||||
|
||||
(image, raw, table)
|
||||
}
|
||||
|
||||
#let i18n-kind(kind) = {
|
||||
let map = toml("/assets/i18n.toml")
|
||||
|
||||
if kind not in map.en {
|
||||
panic("Unknown kind: `" + kind + "`")
|
||||
}
|
||||
|
||||
let lang-map = map.at(text.lang, default: (:))
|
||||
let region-map = if text.region != none {
|
||||
lang-map.at(text.region, default: (:))
|
||||
} else {
|
||||
(:)
|
||||
}
|
||||
let term = region-map.at(kind, default: none)
|
||||
|
||||
if term == none {
|
||||
term = lang-map.at(kind, default: none)
|
||||
}
|
||||
|
||||
if term == none {
|
||||
term = map.en.at(kind)
|
||||
}
|
||||
|
||||
term
|
||||
}
|
||||
|
||||
#let stitch-pairs(args) = {
|
||||
if args.len() == 0 {
|
||||
return ()
|
||||
}
|
||||
|
||||
assert.ne(type(args.first()), label, message: "First item must not be a label")
|
||||
|
||||
let pairs = ()
|
||||
while args.len() != 0 {
|
||||
let item = args.remove(0)
|
||||
if type(item) == label {
|
||||
let last = pairs.pop()
|
||||
|
||||
assert.ne(type(last), label, message: "Cannot have two consecutive labels")
|
||||
|
||||
last.at(1) = item
|
||||
pairs.push(last)
|
||||
} else {
|
||||
pairs.push((item, none))
|
||||
}
|
||||
}
|
||||
|
||||
pairs
|
||||
}
|
||||
|
||||
#let sparse-numbering(numbering) = if type(numbering) == str {
|
||||
let symbols = ("1", "a", "A", "i", "I", "い", "イ", "א", "가", "ㄱ", "\\*")
|
||||
let c = numbering.matches(regex(symbols.join("|"))).len()
|
||||
|
||||
if c == 1 {
|
||||
// if we have only one symbol we drop the super number
|
||||
(_, num) => _numbering(numbering, num)
|
||||
} else {
|
||||
(..nums) => _numbering(numbering, ..nums)
|
||||
}
|
||||
} else {
|
||||
numbering
|
||||
}
|
||||
|
||||
#let _numbering = numbering
|
||||
#let _label = label
|
||||
#let _grid = grid
|
||||
|
||||
/// The counter used for sub figures.
|
||||
#let sub-figure-counter = counter("__subpar:sub-figure-counter")
|
||||
|
||||
/// Creates a figure which may contain other figures, a #emph[super]figure. For
|
||||
/// the meaning of parameters take a look at the regular figure documentation.
|
||||
///
|
||||
/// See @@grid() for a function which places its sub figures in a grid.
|
||||
///
|
||||
/// - kind (str, function): The image kind which should be used, this is mainly
|
||||
/// relevant for introspection and defaults to `image`. This cannot be
|
||||
/// automatically resovled like for normal figures and must be set.
|
||||
/// - numbering (str, function): This is the numbering used for this super
|
||||
/// figure.
|
||||
/// - numbering-sub (str, function): This is the numbering used for the sub
|
||||
/// figures.
|
||||
/// - numbering-sub-ref (str, function): This is the numbering used for
|
||||
/// _references_ to the sub figures. If this is a function, it receives both
|
||||
/// the super and sub figure numbering respectively.
|
||||
/// - supplement (content, function, auto, none): The supplement used for this
|
||||
/// super figure _and_ the sub figures when referenced.
|
||||
/// - propagate-supplement (bool): Whether the super figure's supplement should
|
||||
/// propagate down to its sub figures.
|
||||
/// - caption (content): The caption of this super figure.
|
||||
/// - placement (alignment, auto, none): The float placement of this super
|
||||
/// figure.
|
||||
/// - scope (str): Relative to which containing scope the figure is placed. Set
|
||||
/// this to `"parent"` to create a full-width figure in a two-column document.
|
||||
/// Has no effect if placement is `none`. Can be set to `"parent"` or
|
||||
/// `"column"`.
|
||||
/// - gap (length): The gap between this super figure's caption and body.
|
||||
/// - outlined (bool): Whether this super figure should appear in an outline of
|
||||
/// figures.
|
||||
/// - outlined-sub (bool): Whether the sub figures should appear in an outline
|
||||
/// of figures.
|
||||
/// - label (label, none): The label to attach to this super figure.
|
||||
/// - show-sub (function, auto): A show rule override for sub figures. Recevies
|
||||
/// the sub figure.
|
||||
/// - show-sub-caption (function, auto): A show rule override for sub figure's
|
||||
/// captions. Receives the realized numbering and caption element.
|
||||
/// -> content
|
||||
#let super(
|
||||
kind: image,
|
||||
numbering: "1",
|
||||
numbering-sub: "(a)",
|
||||
numbering-sub-ref: "1a",
|
||||
supplement: auto,
|
||||
propagate-supplement: true,
|
||||
caption: none,
|
||||
placement: none,
|
||||
scope: "column",
|
||||
gap: 0.65em,
|
||||
outlined: true,
|
||||
outlined-sub: false,
|
||||
label: none,
|
||||
show-sub: auto,
|
||||
show-sub-caption: auto,
|
||||
body,
|
||||
) = {
|
||||
t4t.assert.any-type(str, function, kind)
|
||||
|
||||
let assert-numbering = t4t.assert.any-type.with(str, function)
|
||||
assert-numbering(numbering)
|
||||
assert-numbering(numbering-sub)
|
||||
assert-numbering(numbering-sub-ref)
|
||||
|
||||
// adjust numberings to receive either both or the sub number
|
||||
numbering-sub = sparse-numbering(numbering-sub)
|
||||
numbering-sub-ref = sparse-numbering(numbering-sub-ref)
|
||||
|
||||
t4t.assert.any-type(str, content, function, type(auto), type(none), supplement)
|
||||
t4t.assert.any-type(bool, propagate-supplement)
|
||||
t4t.assert.any-type(str, content, type(none), caption)
|
||||
t4t.assert.any(top, bottom, auto, none, placement)
|
||||
t4t.assert.any-type(length, gap)
|
||||
t4t.assert.any-type(bool, outlined)
|
||||
t4t.assert.any-type(bool, outlined-sub)
|
||||
t4t.assert.any-type(_label, type(none), label)
|
||||
|
||||
t4t.assert.any-type(function, type(auto), show-sub)
|
||||
t4t.assert.any-type(function, type(auto), show-sub-caption)
|
||||
|
||||
let function-kinds = (
|
||||
image: "figure",
|
||||
table: "table",
|
||||
raw: "raw",
|
||||
)
|
||||
|
||||
// NOTE: if we use no propagation, then we can fallback to the normal auto behavior, fixing #4.
|
||||
if propagate-supplement and supplement == auto {
|
||||
if repr(kind) in function-kinds {
|
||||
supplement = context i18n-kind(function-kinds.at(repr(kind)))
|
||||
} else {
|
||||
panic("Cannot infer `supplement`, must be set.")
|
||||
}
|
||||
}
|
||||
|
||||
show-sub = t4t.def.if-auto(it => it, show-sub)
|
||||
show-sub-caption = t4t.def.if-auto((num, it) => it, show-sub-caption)
|
||||
|
||||
context {
|
||||
let n-super = counter(figure.where(kind: kind)).get().first() + 1
|
||||
|
||||
[#figure(
|
||||
kind: kind,
|
||||
numbering: n => _numbering(numbering, n),
|
||||
supplement: supplement,
|
||||
caption: caption,
|
||||
placement: placement,
|
||||
scope: scope,
|
||||
gap: gap,
|
||||
outlined: outlined,
|
||||
{
|
||||
// TODO: simply setting it for all doesn't seem to work
|
||||
show: apply-for-all(
|
||||
gather-kinds(body),
|
||||
kind => (
|
||||
inner => {
|
||||
show figure.where(kind: kind): set figure(numbering: _ => _numbering(
|
||||
numbering-sub-ref,
|
||||
n-super,
|
||||
sub-figure-counter.get().first() + 1,
|
||||
))
|
||||
inner
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
set figure(supplement: supplement) if propagate-supplement
|
||||
set figure(outlined: outlined-sub, placement: none)
|
||||
|
||||
show figure: show-sub
|
||||
show figure: it => {
|
||||
let n-sub = sub-figure-counter.get().first() + 1
|
||||
let num = _numbering(numbering-sub, n-super, n-sub)
|
||||
show figure.caption: it => {
|
||||
num
|
||||
[ ]
|
||||
it.body
|
||||
}
|
||||
show figure.caption: show-sub-caption.with(num)
|
||||
|
||||
sub-figure-counter.step()
|
||||
it
|
||||
counter(figure.where(kind: it.kind)).update(n => n - 1)
|
||||
}
|
||||
|
||||
sub-figure-counter.update(0)
|
||||
body
|
||||
},
|
||||
)#label]
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ use crate::{
|
|||
prelude::*,
|
||||
syntax::{Decl, DefKind},
|
||||
ty::{
|
||||
BuiltinTy, InsTy, Interned, PackageId, SigTy, StrRef, Ty, TypeBounds, TypeVar,
|
||||
BuiltinTy, DynTypeBounds, InsTy, Interned, PackageId, SigTy, StrRef, Ty, TypeVar,
|
||||
TypeVarBounds,
|
||||
},
|
||||
};
|
||||
|
@ -197,7 +197,7 @@ impl DocsChecker<'_> {
|
|||
name,
|
||||
def: encoded.clone(),
|
||||
};
|
||||
let bounds = TypeVarBounds::new(var, TypeBounds::default());
|
||||
let bounds = TypeVarBounds::new(var, DynTypeBounds::default());
|
||||
let var = bounds.as_type();
|
||||
self.vars.insert(encoded, bounds);
|
||||
var
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use ecow::{EcoString, EcoVec};
|
||||
use ecow::EcoString;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use reflexo_typst::TypstFileId;
|
||||
|
@ -367,15 +367,45 @@ impl NameBone {
|
|||
}
|
||||
}
|
||||
|
||||
/// The state of a type variable (bounds of some type in program)
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DynTypeBounds {
|
||||
/// The lower bounds
|
||||
pub lbs: rpds::HashTrieSetSync<Ty>,
|
||||
/// The upper bounds
|
||||
pub ubs: rpds::HashTrieSetSync<Ty>,
|
||||
}
|
||||
|
||||
impl From<TypeBounds> for DynTypeBounds {
|
||||
fn from(bounds: TypeBounds) -> Self {
|
||||
Self {
|
||||
lbs: bounds.lbs.into_iter().collect(),
|
||||
ubs: bounds.ubs.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DynTypeBounds {
|
||||
/// Get frozen bounds
|
||||
pub fn freeze(&self) -> TypeBounds {
|
||||
// sorted
|
||||
let mut lbs: Vec<_> = self.lbs.iter().cloned().collect();
|
||||
lbs.sort();
|
||||
let mut ubs: Vec<_> = self.ubs.iter().cloned().collect();
|
||||
ubs.sort();
|
||||
TypeBounds { lbs, ubs }
|
||||
}
|
||||
}
|
||||
|
||||
/// A frozen type variable (bounds of some type in program)
|
||||
/// `t :> t1 | ... | tn <: f1 & ... & fn`
|
||||
/// ` lbs------------- ubs-------------`
|
||||
#[derive(Hash, Clone, PartialEq, Eq, Default, PartialOrd, Ord)]
|
||||
pub struct TypeBounds {
|
||||
/// The lower bounds
|
||||
pub lbs: EcoVec<Ty>,
|
||||
pub lbs: Vec<Ty>,
|
||||
/// The upper bounds
|
||||
pub ubs: EcoVec<Ty>,
|
||||
pub ubs: Vec<Ty>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for TypeBounds {
|
||||
|
@ -1153,7 +1183,7 @@ pub struct TypeScheme {
|
|||
}
|
||||
|
||||
impl TyCtx for TypeScheme {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
fn global_bounds(&self, var: &Interned<TypeVar>, _pol: bool) -> Option<DynTypeBounds> {
|
||||
let v = self.vars.get(&var.def)?;
|
||||
Some(v.bounds.bounds().read().clone())
|
||||
}
|
||||
|
@ -1198,25 +1228,33 @@ impl TypeScheme {
|
|||
}
|
||||
|
||||
/// Converts a type to a type with bounds
|
||||
pub fn to_bounds(&self, def: Ty) -> TypeBounds {
|
||||
let mut store = TypeBounds::default();
|
||||
pub fn to_bounds(&self, def: Ty) -> DynTypeBounds {
|
||||
let mut store = DynTypeBounds::default();
|
||||
match def {
|
||||
Ty::Var(v) => {
|
||||
let w = self.vars.get(&v.def).unwrap();
|
||||
match &w.bounds {
|
||||
FlowVarKind::Strong(w) | FlowVarKind::Weak(w) => {
|
||||
let w = w.read();
|
||||
store.lbs.extend(w.lbs.iter().cloned());
|
||||
store.ubs.extend(w.ubs.iter().cloned());
|
||||
for l in w.lbs.iter() {
|
||||
store.lbs.insert_mut(l.clone());
|
||||
}
|
||||
for l in w.ubs.iter() {
|
||||
store.ubs.insert_mut(l.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ty::Let(v) => {
|
||||
store.lbs.extend(v.lbs.iter().cloned());
|
||||
store.ubs.extend(v.ubs.iter().cloned());
|
||||
for l in v.lbs.iter() {
|
||||
store.lbs.insert_mut(l.clone());
|
||||
}
|
||||
for l in v.ubs.iter() {
|
||||
store.ubs.insert_mut(l.clone());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
store.ubs.push(def);
|
||||
store.ubs.insert_mut(def);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1269,10 +1307,10 @@ impl fmt::Debug for TypeVarBounds {
|
|||
|
||||
impl TypeVarBounds {
|
||||
/// Create a type variable bounds
|
||||
pub fn new(var: TypeVar, init: TypeBounds) -> Self {
|
||||
pub fn new(var: TypeVar, init: DynTypeBounds) -> Self {
|
||||
Self {
|
||||
var: Interned::new(var),
|
||||
bounds: FlowVarKind::Strong(Arc::new(RwLock::new(init))),
|
||||
bounds: FlowVarKind::Strong(Arc::new(RwLock::new(init.clone()))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1301,15 +1339,15 @@ impl TypeVarBounds {
|
|||
#[derive(Clone)]
|
||||
pub enum FlowVarKind {
|
||||
/// A type variable that receives both types and values (type instances)
|
||||
Strong(Arc<RwLock<TypeBounds>>),
|
||||
Strong(Arc<RwLock<DynTypeBounds>>),
|
||||
/// A type variable that receives only types
|
||||
/// The received values will be lifted to types
|
||||
Weak(Arc<RwLock<TypeBounds>>),
|
||||
Weak(Arc<RwLock<DynTypeBounds>>),
|
||||
}
|
||||
|
||||
impl FlowVarKind {
|
||||
/// Get the bounds of the type variable
|
||||
pub fn bounds(&self) -> &RwLock<TypeBounds> {
|
||||
pub fn bounds(&self) -> &RwLock<DynTypeBounds> {
|
||||
match self {
|
||||
FlowVarKind::Strong(w) | FlowVarKind::Weak(w) => w,
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub trait TyCtx {
|
|||
/// Get local binding of a variable.
|
||||
fn local_bind_of(&self, _var: &Interned<TypeVar>) -> Option<Ty>;
|
||||
/// Get the type of a variable.
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds>;
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<DynTypeBounds>;
|
||||
}
|
||||
|
||||
impl TyCtx for () {
|
||||
|
@ -37,7 +37,7 @@ impl TyCtx for () {
|
|||
None
|
||||
}
|
||||
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<TypeBounds> {
|
||||
fn global_bounds(&self, _var: &Interned<TypeVar>, _pol: bool) -> Option<DynTypeBounds> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ impl TypeSimplifier<'_, '_> {
|
|||
|
||||
fn transform(&mut self, ty: &Ty, pol: bool) -> Ty {
|
||||
match ty {
|
||||
Ty::Let(w) => self.transform_let(w, None, pol),
|
||||
Ty::Let(w) => self.transform_let(w.lbs.iter(), w.ubs.iter(), None, pol),
|
||||
Ty::Var(v) => {
|
||||
if let Some(cano) = self.cano_local_cache.get(&(v.def.clone(), self.principal)) {
|
||||
return cano.clone();
|
||||
|
@ -177,7 +177,7 @@ impl TypeSimplifier<'_, '_> {
|
|||
FlowVarKind::Strong(w) | FlowVarKind::Weak(w) => {
|
||||
let w = w.read();
|
||||
|
||||
self.transform_let(&w, Some(&v.def), pol)
|
||||
self.transform_let(w.lbs.iter(), w.ubs.iter(), Some(&v.def), pol)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -251,19 +251,25 @@ impl TypeSimplifier<'_, '_> {
|
|||
}
|
||||
|
||||
#[allow(clippy::mutable_key_type)]
|
||||
fn transform_let(&mut self, w: &TypeBounds, def_id: Option<&DeclExpr>, pol: bool) -> Ty {
|
||||
let mut lbs = HashSet::with_capacity(w.lbs.len());
|
||||
let mut ubs = HashSet::with_capacity(w.ubs.len());
|
||||
fn transform_let<'a>(
|
||||
&mut self,
|
||||
lbs_iter: impl ExactSizeIterator<Item = &'a Ty>,
|
||||
ubs_iter: impl ExactSizeIterator<Item = &'a Ty>,
|
||||
def_id: Option<&DeclExpr>,
|
||||
pol: bool,
|
||||
) -> Ty {
|
||||
let mut lbs = HashSet::with_capacity(lbs_iter.len());
|
||||
let mut ubs = HashSet::with_capacity(ubs_iter.len());
|
||||
|
||||
crate::log_debug_ct!("transform let [principal={}] with {w:?}", self.principal);
|
||||
crate::log_debug_ct!("transform let [principal={}]", self.principal);
|
||||
|
||||
if !self.principal || ((pol) && !def_id.is_some_and(|i| self.negatives.contains(i))) {
|
||||
for lb in w.lbs.iter() {
|
||||
for lb in lbs_iter {
|
||||
lbs.insert(self.transform(lb, pol));
|
||||
}
|
||||
}
|
||||
if !self.principal || ((!pol) && !def_id.is_some_and(|i| self.positives.contains(i))) {
|
||||
for ub in w.ubs.iter() {
|
||||
for ub in ubs_iter {
|
||||
ubs.insert(self.transform(ub, !pol));
|
||||
}
|
||||
}
|
||||
|
@ -285,8 +291,6 @@ impl TypeSimplifier<'_, '_> {
|
|||
let mut ubs: Vec<_> = ubs.into_iter().collect();
|
||||
ubs.sort();
|
||||
|
||||
let mut lbs = lbs.into_iter().collect();
|
||||
let mut ubs = ubs.into_iter().collect();
|
||||
Ty::Let(TypeBounds { lbs, ubs }.into())
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ mod tests {
|
|||
use insta::{assert_debug_snapshot, assert_snapshot};
|
||||
use tinymist_derive::BindTyCtx;
|
||||
|
||||
use super::{Interned, Ty, TyCtx, TypeBounds, TypeScheme, TypeVar};
|
||||
use super::{DynTypeBounds, Interned, Ty, TyCtx, TypeScheme, TypeVar};
|
||||
use crate::ty::tests::*;
|
||||
use crate::ty::ApplyChecker;
|
||||
#[test]
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::analysis::{func_signature, BuiltinTy, PathPreference, Ty};
|
|||
use crate::syntax::{
|
||||
descending_decls, interpret_mode_at, is_ident_like, CheckTarget, DescentDecl, InterpretMode,
|
||||
};
|
||||
use crate::ty::{Iface, IfaceChecker, InsTy, SigTy, TyCtx, TypeBounds, TypeScheme, TypeVar};
|
||||
use crate::ty::{DynTypeBounds, Iface, IfaceChecker, InsTy, SigTy, TyCtx, TypeScheme, TypeVar};
|
||||
use crate::upstream::complete::complete_code;
|
||||
|
||||
use crate::{completion_kind, prelude::*, LspCompletion};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue